perm filename TELNET.FAI[NET,MRC] blob sn#301704 filedate 1977-08-22 generic text, type C, neo UTF8
COMMENT ⊗   VALID 00069 PAGES
C REC  PAGE   DESCRIPTION
C00001 00001
C00006 00002	<MRC>TELNET.FAI3    06-AUG-77 09:13:24    TECO'd by MRC
C00013 00003		TITLE TELNET (USER)
C00015 00004	SET VARPC,100000	 Where to store variables
C00017 00005	 Program starts here
C00019 00006		SUB P,[XWD 2,2]
C00022 00007	 Main command loop
C00024 00008	 drops in
C00026 00009	 Abnormal interrupts come here
C00028 00010	ESCINV:	MOVEI A,101
C00030 00011	 Get a character
C00033 00012	UCS1:	SKIPG A,UCASC
C00035 00013	.NOUT:	NOUT
C00036 00014	 Uuo handler
C00037 00015	 Map fork one to one with this fork through page 177
C00039 00016	 Macro for generating commands
C00042 00017	YNT:	CC(<signal.waiting.output>,<MOVEM NOA,SWOFLG>)
C00044 00018	 Command table for echo modes
C00047 00019	 Connection name table
C00049 00020	 Symbol evaluator
C00051 00021	DELCH:	CAMN PTR,BPTR		 Delete character, any to delete?
C00052 00022	 End of symbol, try lookup
C00054 00023	PRQUES:	PUSHJ P,ECHOIT
C00056 00024	 Lookup symbol
C00059 00025	SYMCMP:	CAIN B,"*"		 Asterisk
C00061 00026	SYMCLS: ILDB B,Y		 Get class indicator
C00062 00027	SYMNCL:	PUSHJ P,SYMCLS
C00063 00028	 News
C00065 00029	CONN2:	HRROI A,[ASCIZ /is /]
C00066 00030	CONN3:	PUSHJ P,INIFRK
C00068 00031	CONFL1:CONFL0:	HRROI A,[ASCIZ /,
C00069 00032	 Perform icp
C00070 00033	ICPA:	MOVE B,-2(P)		 Get beginning of string
C00072 00034	ICPB:	MOVE B,0(P)		 Beginning of string
C00074 00035	ICPFL2:	SUB P,[XWD 2,2]
C00075 00036	OPNWAT:	PUSH P,A
C00077 00037	 Disconnect
C00079 00038	 Set name for connection
C00081 00039	 List connections
C00082 00040	 Set mode switches
C00083 00041	WRTMDF:	MOVE TAB,HOSTAB
C00085 00042	OPNMDF:	MOVEI A,400000
C00086 00043	 Status.of
C00087 00044	 Exec
C00088 00045	 Netstatus
C00090 00046	 Set escape character
C00092 00047	 Set terminal modes
C00094 00048	 Echo.mode.is
C00096 00049	 Set control character echoing
C00097 00050	 Print current modes
C00099 00051	PCMDTB:	XWD RAISEF,[ASCIZ /Raise/]
C00102 00052	TYPAL:	PUSHJ P,.PBIN
C00103 00053	 Typescript to a file
C00105 00054	 Get uniform time in secs
C00107 00055	 Divert output to a file
C00108 00056	 Print where we are
C00110 00057	drops in
C00112 00058	 Quit, exit back to exec
C00114 00059	 Set remote mode
C00115 00060	 Other routines
C00117 00061	SEND:	CIS
C00120 00062	SEND3:	SKIPN LNBFF(CNX)	 If not line buffering
C00121 00063	SFTDWN:	AOSE LCASCF
C00123 00064	SNDLBF:	CAIE A,"A"-100
C00124 00065	RECV:	CIS
C00127 00066	RECVS:	MOVNI A,SAVBFS		 Prepare wrapped pointer
C00129 00067	RECVFL:	MOVEM B,D
C00131 00068	RCVCTL:	CAIN B,TELASC
C00133 00069	RCVINS:	PUSH P,A
C00135 ENDMK
C⊗;
;<MRC>TELNET.FAI;3    06-AUG-77 09:13:24    TECO'd by MRC
; Updated to correspond to latest BBN version
;<CCA-NETWORK>TELNET.FAI;5    19-DEC-74 02:06:55    EDIT BY HGM
;<CCA-NETWORK>TELNET.FAI;4    29-SEP-74 11:10:42    EDIT BY HGM
; Adding a bit of fork setup PMAPs so can debug ↑C↑C glitch
;<CCA-NETWORK>TELNET.FAI;3    12-JUL-73 00:05:30	EDIT BY HGM
;<CCA-NETWORK>TELNET.FAI;2    23-JUN-73 08:08:56	EDIT BY HGM
;<CCA-NETWORK>TELNET.FAI;1     7-FEB-73 19:22:17	EDIT BY HGM
; Recovering <DOCUMENTATION>
;<SOURCES>TELNET.FAI;28    18-JAN-73 11:20:44	EDIT BY TOMLINSON
;<SOURCES>TELNET.FAI;27    17-JAN-73 16:46:23	EDIT BY TOMLINSON
;<SOURCES>TELNET.FAI;26    16-JAN-73 10:52:09	EDIT BY TOMLINSON
; Deleted surveying and time constant. Revamped receive fork.
;<TOMLINSON>TELNET.FAI;13    15-JAN-73 14:02:33	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;12    15-JAN-73 13:43:16	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;11    15-JAN-73 13:13:11	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;10    15-JAN-73 12:29:13	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;9    15-JAN-73 11:57:40	EDIT BY TOMLINSON
;<TOMLINSON>MESSAGE.TXT;2    14-JAN-73 17:10:46	EDIT BY TOMLINSON
;		↑↑↑	Looks like he glitched on this one!! - MRC
;<TOMLINSON>TELNET.FAI;6    14-JAN-73 16:51:00	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;5    14-JAN-73 13:50:18	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;4    14-JAN-73 13:20:44	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;3    11-JAN-73 14:12:15	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;2    11-JAN-73 13:32:49	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;1    11-JAN-73 12:36:52	EDIT BY TOMLINSON
;<SOURCES>TELNET.FAI;25    10-SEP-72 10:07:17	EDIT BY TOMLINSON
;<SOURCES>TELNET.FAI;24     8-SEP-72 10:02:57	EDIT BY TOMLINSON
;<SOURCES>TELNET.FAI;23     8-SEP-72  9:08:11	EDIT BY TOMLINSON
;<SOURCES>TELNET.FAI;22     5-SEP-72 11:37:29	EDIT BY TOMLINSON
;<SOURCES>TELNET.FAI;21     5-SEP-72 11:33:24	EDIT BY TOMLINSON
;<SOURCES>TELNET.FAI;20     5-SEP-72 11:17:41	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;46     3-SEP-72 11:37:58	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;45     2-SEP-72 16:02:59	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;44     2-SEP-72 15:56:36	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;43     2-SEP-72 15:54:09	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;42     2-SEP-72 15:28:21	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;41     2-SEP-72 15:13:34	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;40     2-SEP-72 14:54:29	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;39     2-SEP-72 14:45:07	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;38     2-SEP-72 14:43:04	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;37     2-SEP-72 14:19:33	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;36     2-SEP-72 13:59:08	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;35     2-SEP-72 13:57:07	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;34     2-SEP-72 12:04:40	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;33     2-SEP-72 11:33:29	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;32    28-JUL-72 15:15:14	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;31    28-JUL-72 14:24:37	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;30    28-JUL-72 14:17:41	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;29    28-JUL-72 13:27:03	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;28    28-JUL-72 11:42:16	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;27    28-JUL-72 11:23:30	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;26    28-JUL-72 11:09:29	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;25    28-JUL-72 10:53:32	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;24    28-JUL-72 10:29:02	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;23    27-JUL-72 16:59:25	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;22    27-JUL-72 16:01:50	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;21    27-JUL-72 15:55:01	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;20     3-JUL-72 13:29:08	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;19     3-JUL-72 13:22:25	EDIT BY TOMLINSON
;<TOMLINSON>TELNET.FAI;10    29-JUN-72 21:15:41	EDIT BY TOMLINSON
	TITLE TELNET (USER)
	SUBTTL	R.S.Tomlinson

VERNUM:	ASCIZ \4.0 August 6, 1977\]
	BLOCK 3

OPDEF	ERROR [1B8]

; Accumulators

A←1
B←2
C←3
D←4
X←5
Y←6
Z←7
PTR←10
TAB←11
NOA←12
CNX←13
NCNX←14
P←17
F←0

; Flags (rh of f)

REMOTF←←1		; Operating in remote mode
COMMDF←←4		; In command mode
NSTIWF←←2		; Don't do STIW's
TMPF←←400000		; Temporary flags
TMPF2←←200000

; Parameters

NPDL←←2000		; Size of push list
NCONN←←7		; Number of connections to remember
NHSTW←←(=256+=35)/=36	; Number of words in host bit tables
IESC←←"Z"-100		; Initial escape character
ICBF←←"O"-100		; Initial clear output buffer character
TELSNC←←200		; Sync sequence to serving site
TELBRK←←201		; Break character
TELNOP←←202		; Telnet nop character
TELNEC←←203		; Don't echo
TELECH←←204		; Do echo
TELHID←←205		; Hide input
TELASC←←240		; Use ASCII
ESCCHN←←0		; Use channel 0 for escape
ABNCHN←←2		; Channel 2 for abnormal connection termination
NTICHN←←3		; Channel 3 for network PSI's
CBFCHN←←4
SAVBFS←←4000		; Size of string saving buffer
SET VARPC,100000	; Where to store variables

; Variables etc.

ARRAY	HOSTRG[4*=256]
ARRAY	SHOSTB,NHOSTB[=256]
INTEGER	SHSTAB,NHSTAB,CONTAB
ARRAY	PDL[NPDL]
ARRAY	COMBUF[200]
ARRAY	BIGBUF[4000]
INTEGER	LODFLG,WATFLG,TCASE,TRMLWC
INTEGER	BPTR,LPTR,SVP
INTEGER	TTCOC0,TTCOC1,TTMOD0,TTMODR,TTMODC,JOBTIW,HDX,NFANCY
INTEGER	ESCAPE,ESCCOD,CBFCHR,CBFCOD,LSTBDI,CONCSF
INTEGER	ABNLCK,ABNCNX
INTEGER	LCASCF,UCASCF
INTEGER	LCASC,LCASL,UCASC,UCASL,UNSFT
INTEGER	BRKC,SYNC,QUOT,QUOTF
ARRAY	FAC[20]
INTEGER	IJFN,JJFN,AJFN,SCRJFN,SCRCNT,SCRTIM
INTEGER	DIVJFN,DIVSWT,RLACJ,SPCFRK
INTEGER	SKTMSK,FSKT,FHST,FHSTN,RETPC1,RETPC2,RETPC3
ARRAY	SNDJFN,RCVJFN,SNDFRK,RCVFRK,LSKT,ELCLF,LFCRF,LNBFF[NCONN+1]
ARRAY	XPARNT,CBFCNT[NCONN+1]
ARRAY	RAISEF,LOWERF,ECHCOC,CONTB,SAVINP,SAVINC,SAVONP,SAVSWT[NCONN+1]
ARRAY	CONNAM[3+3*NCONN]
INTEGER	ICPTIM,SUMTOT,SUMPHC,SUMSCL,SUMTIM,SUMTM2,SUMFST,SUMSRT,SWOFLG
ARRAY	SUMAVG,SUMAVC,SUMUPT,SUMUPC,SUMTTC[400]
INTEGER	TERM
INTEGER	JUNK
INTEGER	NTICNT,NTIIA,CLROBF
ARRAY	LINBUF[200]

SET FRKPC,200000
USE FRKPC

SPDL:	BLOCK 100
FKRET1:	BLOCK 1
FKRET2:	BLOCK 1
FKRET3:	BLOCK 1
SAVBUF:	BLOCK SAVBFS

USE
; Program starts here

START:	HRROI A,[ASCIZ /
User Telnet /]
	PSOUT
	HRROI A,VERNUM
	PSOUT
	HRROI A,[ASCIZ /.  Type HELP<cr> for help./]
	PSOUT
RSTART:	RESET			; Reset the world
	MOVE P,[XWD -NPDL,PDL-1]
	MOVE A,[PUSHJ P,UUO]
	MOVEM A,41
	MOVEI A,400000
	RPCAP			; Find out what we can do
	AND B,[1B0!1B2]
	IOR C,B
	EPCAP			; Enable control-C stealing
	TLNE C,(1B0)
	 TROA F,NSTIWF
	TRZ F,NSTIWF
	SETZB F,VARS
	MOVE A,[XWD VARS,VARS+1]
	BLT A,EVARS-1		; Zero all variables
	MOVE A,[SIXBIT /HOSTN/]
	SYSGT
	PUSH P,B
	MOVE A,[SIXBIT /HSTNAM/]
	SYSGT
	PUSH P,B
	MOVEI Y,NHOSTB-1
	MOVEI X,SHOSTB-1
	MOVEI C,HOSTRG-1
	HLLZ D,-1(P)
GTHSTL:	HRRZ A,-1(P)
	HRL A,D
	GETAB
	 JRST 4,.-1
	MOVEI B,1(C)
	HRLI B,(<POINT 7,0>)
	TLNN A,(1B0)
	 JRST [	PUSH Y,B
		JRST .+2]
	PUSH X,B
	MOVE B,A
GTHSTE:	HRRZ A,0(P)		; Hostab number
	HRL A,B			; Offset
	GETAB
	 JRST 4,.-1
	PUSH C,A		; Store in hostrg
	TRNE A,377		; Done when reach null byte
	 AOJA B,GTHSTE		; Loop
	LDB A,[POINT 9,B,17]
	PUSH C,[PUSHJ P,.CVHST]
	PUSH C,A
GTHSTN:	AOBJN D,GTHSTL
	HLLZS X
	HLLZS Y
	MOVNS X
	MOVNS Y
	HRRI X,SHOSTB
	HRRI Y,NHOSTB
	MOVEM X,SHSTAB
	MOVEM Y,NHSTAB
	SUB P,[XWD 2,2]
	SETOM ABNLCK		; Unlock abnormal interrupt handler.
	FOR VAR IN (UCASC,UCASL,LCASC,LCASL,UNSFT,QUOT,BRKC,SYNC)
<	SETOM VAR
>
	MOVSI B,-NCONN
ICNVL:	MOVE A,[BYTE (1)0,0,0,0,0,0,0,1,0,1,1,0,0,1]
	MOVEM A,ECHCOC(B)	; Initial control character local echo
	SETOM LFCRF(B)
	SETOM ELCLF(B)
	AOBJN B,ICNVL
	MOVEI A,CONTB
	MOVEM A,CONTAB		; CONTAB points at CONTB
	SETZ NOA,
	PUSHJ P,SETSCR		; Set up for typescript
	MOVEI A,IESC		; Setup initial escape character
	MOVEM A,ESCAPE
	PUSHJ P,CVINTC		; Convert character to interrup channel
	 JRST 4,.		; Can't fail
	MOVEM A,ESCCOD
	MOVEI A,ICBF
	MOVEM A,CBFCHR
	PUSHJ P,CVINTC
	 JRST 4,.
	MOVEM A,CBFCOD
	MOVEI A,400000
	CIS
	MOVE B,[XWD LEVTAB,CHNTAB]
	SIR
	EIR
	MOVEI A,100
	RFMOD			; Find out what kind of line we have
	MOVEM B,TTMOD0		; Remember same
	TRNE B,1B32		; Hdx terminal?
	 SETOM HDX		; Yes, set HDX flag
	TLNE B,(1B3)
	 SETOM TRMLWC		; Remember term has lower case
	ANDCMI B,77B23!3B25!17B29!1B30!1B31
	PUSH P,B
	IORI B,17B23!0B25!1B29
	MOVEM B,TTMODC		; In command mode: break-all, echo-none
	POP P,B
	IORI B,17B23!1B29
	MOVEM B,TTMODR		; No change for remote mode
	RFCOC			; Get standard control output control
	MOVEM B,TTCOC0
	MOVEM C,TTCOC1
	MOVEI A,ESCCHN		; PSI channel
	HRL A,ESCCOD		; Escape terminal code
	ATI
	MOVEI A,CBFCHN
	HRL A,CBFCOD
	ATI			; Assign
	MOVE B,[1⊗<43-ESCCHN>!1⊗<43-ABNCHN>!1⊗<43-NTICHN>!1⊗<43-CBFCHN>!1B9!1B11!1B15!7B18]
	MOVEI A,400000
	AIC			; Activate interrupt channel
; Main command loop

COMLP:	TRO F,COMMDF
	MOVEI A,101
	DOBE
	MOVE P,[XWD -NPDL,PDL-1]
	MOVE NCNX,CNX
	SETO B,
	MOVEI A,-5
	TRNN F,NSTIWF
	 STIW			; Restore terminal interrupt word
	MOVEI A,100
	MOVE B,TTMODC
	SKIPE NFANCY
	 JRST [	TRZ B,77B23
		TRO B,2B25!16B23
		JRST .+1]
	SFMOD			; Set tty mode for command input
	MOVE B,[BYTE (2)0,0,1,1,1,1,1,2,0,2,2,1,2,2,1,1,1,1]
	MOVE C,[BYTE (2)0,1,1,1,1,1,0,1,1,0,1,1,1,2]
	SFCOC
	HRROI A,[ASCIZ /
#/]
	PUSHJ P,.PSOUT		; Prompt character
	MOVE PTR,[POINT 7,COMBUF-1,34]
	MOVEM PTR,LPTR		; Pointer to beginning of line
	MOVEI A," "
	IDPB A,PTR		; Deposit initial space to line up
	MOVE TAB,COMTAB		; Setup to use COMTAB
	PUSHJ P,SYMVAL		; Call symbol evaluator
	SKIPE SNDJFN(CNX)
	 TRNN F,REMOTF		; Remote mode?
	  JRST COMLP		; No. stay in command mode
	TRZ F,COMMDF
	MOVEI A,"#"
	PUSHJ P,.PBOUT
	MOVEI A,37
	PUSHJ P,.PBOUT
	MOVEI A,-5
	MOVN C,ESCCOD
	MOVSI B,400000
	ROT B,(C)		; Get bit for escape code
	PUSH P,B
	MOVN C,CBFCOD
	MOVSI B,400000
	ROT B,0(C)
	IORM B,0(P)
	POP P,B
	IORI B,1B30		; Include carrier off
	TRNN F,NSTIWF
	 STIW			; And set TIW to that
; falls through
; drops in
	MOVEI A,100
	MOVE B,TTMODR
	SKIPE XPARNT(CNX)
	 TRZ B,3B29
	SFMOD			; Set TTY mode for remote
	MOVE A,RCVFRK(CNX)
	FFORK			; Freeze it
	MOVEI A,400000
	DIR			; Interrupts off to avoid confusion
	SETZM SAVSWT(CNX)	; Resume output
	MOVE A,RCVFRK(CNX)
	RFSTS			; Get PC of receive fork
	MOVE A,RCVFRK(CNX)
	HRRZS B
	CAILE B,RECV0		; If fork will get back to RECV0
	 CAILE B,RECVB+1
	  JRST REST2		; Skip the following
	MOVEI B,RECV0
	SFORK			; Restart fork
REST2:	MOVEI A,400000
	EIR
	MOVE A,RCVFRK(CNX)
	RFORK			; And resume
	MOVE A,SNDFRK(CNX)
	RFORK			; Resume send fork
	WFORK			; Should wait forever
	HRROI A,[ASCIZ /
Funny fork termination. Restarted./]
	PUSHJ P,.PSOUT
	JRST RSTART
; Abnormal interrupts come here

BADINT:	MOVEI A,101
	DOBE
	TIME
	SUBI A,=15000
	CAMGE A,LSTBDI		; Within 5 seconds of last bad int?
	 JRST BADBAD		; Very bad
	HRROI A,[ASCIZ /
Abnormal interrupt from location /]
	PUSHJ P,.PSOUT
	HRRZ B,RETPC1
	MOVEI C,10
	MOVEI A,101
	PUSHJ P,.NOUT
	 JFCL
	HRROI A,[ASCIZ /.
/]
	PUSHJ P,.PSOUT
	TIME
	MOVEM A,LSTBDI
	JRST ESCINZ

BADBAD:	HALTF
	JRST BADINT

; If remote host initiates disconnect, rec'v fork inits int'rpt to here

ABNINT:	MOVE X,ABNCNX		; Get the correct context
	PUSHJ P,DISC1
	JRST ESCINZ

; Clear outbuf int comes here

CBFINT:	SKIPE SNDJFN(CNX)
	AOSE QUOTF
	 JRST CBFINZ
	PUSH P,B
	MOVEI B,SENDO
	JRST SPCSND

CBFINZ:	SETOM CLROBF
	PUSH P,A
	MOVEI A,101
	CFOBF
	POP P,A
	DEBRK
	DEBRK

; Escape interrupt comes to here

ESCINT:	SKIPE SNDJFN		; If connection exists,
	 AOSE QUOTF		; And quote prefix typed,
	  JRST ESCINV
	PUSH P,B
	MOVEI B,SENDE
SPCSND:	PUSH P,A		; Then sent escape character
	MOVE A,SNDFRK(CNX)
	FFORK
	SFORK
	RFORK
	POP P,A
	POP P,B
	DEBRK
ESCINV:	MOVEI A,101
	TRNE COMMDF		; Command mode?
	 CFOBF			; Yes, flush output
ESCINZ:	MOVEI A,100
	CFIBF
	SKIPE RLACJ		; Is there likely to be a JFN in ac 1?
	 TDNE A,[XWD -1,700000]
	  SKIPA			; Apparently not
	   PUSHJ P,CLRJFN	; Apparently yes
	SETZM RLACJ
	SKIPE A,SNDFRK(CNX)	; If there is a send fork
	 FFORK			; Freeze it
	SKIPN RCVJFN(CNX)	; Connected?
	 JRST ESCINW		; No, skip this
	SETOM SAVSWT(CNX)	; Switch to saving input
	MOVE A,RCVFRK(CNX)
	RFORK			; Leave running
ESCINW:	SKIPE A,SPCFRK		; If there is a special fork
	 KFORK			; Kill it
	SETZM SPCFRK
	FOR JFN IN (AJFN,JJFN,IJFN),<
	SKIPE A,JFN
	 PUSHJ P,CLRJFN
	SETZM JFN>		; Release temporary JFN's
ESCI1:	MOVE A,[XWD 10000,COMLP]
	MOVEM A,RETPC1
	DEBRK			; DEBRK back to COMLP

LEVTAB:	RETPC1
	RETPC2
	RETPC3

CHNTAB:	REPEAT ESCCHN,<XWD 1,BADINT>
	XWD 1,ESCINT
	0
	XWD 1,ABNINT
	XWD 3,NTIINT
	XWD 2,CBFINT
	REPEAT <=36-5-ESCCHN>,<XWD 1,BADINT>

FKLVT:	FKRET1
	FKRET2
	FKRET3

FKCHT:	0
	XWD 3,RCVINS
	REPEAT =8,<0>
	XWD 2,RCVEOF
	XWD 1,IOERR
	REPEAT =36-=12,<0>
; Get a character

GCH:	PUSHJ P,.PBIN
	CAIE A,177
CPOPJ:	 POPJ P,
	HRROI A,[ASCIZ /XXX/]
	PUSHJ P,.PSOUT
	JRST COMLP

; Echo character in a

ECHOIT:	SKIPE HDX
	 PUSHJ P,PBOUT0
	SKIPE HDX
	 POPJ P,
	SKIPE NFANCY
	 TRNN F,COMMDF
	  PUSHJ P,.PBOUT
	POPJ P,

; Primary output with case indicate

.PEOUT:	PUSHJ P,PBOUT0
	CAIL A,100		; Does character have case?
	 SKIPE TRMLWC		; Or does terminal have lower case?
	  JRST EOUTX1		; Caseless
	SKIPGE LCASL
	 SKIPL LCASC
	  SKIPA
	   JRST EOUTX1		; Don't indicate if shift chars absent
	SKIPGE UCASL
	 SKIPL UCASC
	  SKIPA
	   JRST EOUTX1
	CAIE A,177
	 CAIN A,137
	  JRST EOUTX1
	PUSH P,B
	MOVE B,A
	ANDI B,40		; Extract case
	ANDCMI A,40		; Force upper
	CAMN B,TCASE		; Same as current case?
	 JRST EOUTX0		; No need to indicate
	PUSH P,A
	JUMPE B,IUPC		; Upper case
	SKIPG A,LCASL		; Do we have a lower case lock?
	 JRST LCS1		; No, try for lowercase char
	PBOUT			; Yes, print it
	MOVEM B,TCASE		; And remember new case
	JRST EOUTX

LCS1:	SKIPG A,LCASC		; Have we a lower case char prefix?
	 JRST EOUTX		; No, can't indicate
	PBOUT			; Yes, print it
	JRST EOUTX		; But don't change case

IUPC:	SKIPG A,UCASL		; Do we have a upper case lock
	 JRST UCS1
	PBOUT
	MOVEM B,TCASE
	JRST EOUTX
UCS1:	SKIPG A,UCASC
	 JRST EOUTX
	PBOUT
EOUTX:	POP P,A
EOUTX0:	POP P,B
EOUTX1:	CAME A,UCASC
	 CAMN A,UCASL
	  JRST ESPCL
	CAME A,LCASC
	 CAMN A,LCASL
	  JRST ESPCL
	CAME A,QUOT
	 CAMN A,BRKC
	  JRST ESPCL
	PBOUT
	POPJ P,

ESPCL:	PUSH P,A
	SKIPLE A,QUOT
	 PBOUT
	POP P,A
	PBOUT
	POPJ P,

; Primary input

.PBIN:	PUSH P,B
	MOVEI A,100
	RFMOD			; Will echo be generated?
	TRNE B,3B33!3B25
	 JRST [	MOVEI B,PBOUT0
		EXCH B,0(P)
		JRST .+2]
	POP P,B
	PBIN
	POPJ P,

; Primary output

.PBOUT:	PBOUT
PBOUT0:	SKIPN SCRJFN
	 POPJ P,
	PUSH P,B
	MOVE B,A
	MOVE A,SCRJFN
	BOUT
	PUSHJ P,SCRUPD
	MOVE A,B
	POP P,B
	POPJ P,

.GTJFN:	MOVE B,[XWD 100,101]
GTJFN0:	SETOM RLACJ
	GTJFN
	 JRST [	SETZM RLACJ
		POPJ P,]
	MOVEM A,IJFN
	SETZM RLACJ
	PUSH P,C
	SETZ C,
	MOVE B,A
	SKIPE A,SCRJFN
	 JFNS
	POP P,C
	PUSHJ P,SCRUPD
	MOVE A,B
	JRST SKPRET
.NOUT:	NOUT
	 POPJ P,
	SKIPE A,SCRJFN
	 NOUT
	  JFCL
	PUSHJ P,SCRUPD
	MOVEI A,101
	AOS (P)
	POPJ P,

.SOUT:	SKIPN A,SCRJFN
	 JRST .SOUT0
	PUSH P,B
	PUSH P,C
	SOUT
	PUSHJ P,SCRUPD
	POP P,C
	POP P,B
.SOUT0:	MOVEI A,101
	SOUT
	POPJ P,

.PSOUT:	SKIPE SCRJFN
	PUSH P,A
	PSOUT
	SKIPN SCRJFN
	 POPJ P,
	EXCH B,0(P)
	PUSH P,C
	MOVE A,SCRJFN
	SETZ C,
	SOUT
	PUSHJ P,SCRUPD
	MOVE A,B
	POP P,C
	POP P,B
	POPJ P,
; Uuo handler

UUO:	HRRO A,40
	PUSHJ P,ERROUT
	MOVEI A,400000
	CIS
	EIR
	JRST COMLP

ERROUT:	PUSH P,A
	MOVEI A,101
	DOBE
	POP P,A
	PUSHJ P,.PSOUT
	MOVEI A,=1000
	DISMS
	MOVEI A,100
	CFIBF
	POPJ P,

; Convert interrupt character to code

CVINTC:	CAIG A,33
	 JRST SKPRET
	CAIE A,177
	 CAIN A,40
	  SKIPA
	   POPJ P,
	CAIN A,40
	 MOVEI A,=29
	CAIN A,177
	 MOVEI A,=28
	JRST SKPRET
; Map fork one to one with this fork through page 177
; Call:	A	; Fork handle
;	PUSHJ P,MAPFRK
; Returns
;	+1	; Always. transparent

MAPFRK:	PUSH P,C
	PUSH P,D
	PUSH P,B
	MOVSI D,-177
	MOVSI B,(A)
	MOVSI A,400000
	MOVSI C,160000
MAPFK1:	HRR A,D
	HRR B,D
	PMAP
	AOBJN D,MAPFK1
	MOVE D,[XWD -10,770]	; DDT too
MAPFK2:	HRR A,D
	HRR B,D
	PMAP
	AOBJN D,MAPFK2
	EXCH A,B
	TRZ A,-1
	HLR B,A
	TRC B,400600
	PMAP
	HLRZ A,A
	POP P,B
	POP P,D
	POP P,C
	POPJ P,

INIFRK:	MOVEM NCNX,CNX+FAC
	MOVEI B,FAC
	SFACS
	MOVE B,[XWD FKLVT,FKCHT]
	CIS
	SIR
	EIR
	MOVSI B,(1B1!1B10!1B11)
	AIC
	POPJ P,

; Close and release JFN

CLRJFN:	PUSH P,A
	CLOSF
	 JFCL
	POP P,A
	RLJFN
	 JFCL
	POPJ P,
; Macro for generating commands

DEFINE	CC(STR,VAL)<
	POINT 7,[ASCIZ \STR\
		VAL]
>

; Top level commands

TOPC:	XWD -1,SHSTAB
	XWD -1,NULTAB
	CC(<;*%x>,<JRST DOCOMT>)
	CC(<flush.host>,<PUSHJ P,.FLUSH>)
	CC(<list.connections>,<PUSHJ P,LSTCON>)
	CC(<where.am.I>,<PUSHJ P,.WHERE>)
	CC(<wait.for.any.active.connection>,<PUSHJ P,WATRET>)
	CC(<retrieve.connection.under.name>,<PUSHJ P,RETCON>)
	CC(<name.current.connection.to.be>,<PUSHJ P,.STNAM>)
	CC(<write.modes.for.host>,<PUSHJ P,WRTMDF>)
	CC(<!synch!>,<PUSHJ P,SNDSNC>)
	CC(<!break!>,<PUSHJ P,SNDBRK>)
	CC(<control>,<PUSHJ P,SNDCTL>)
	XWD -1,CODTB
	CC(<code>,<JRST [	MOVE TAB,CODTB
				JRST SYMVAL]>)
	CC(<exec>,<PUSHJ P,.EXEC>)
	CC(<ddt>,<JRST 770000>)
	CC(<reset>,<PUSHJ P,.RESET>)
	CC(<logout>,<PUSHJ P,.LGOUT>)
	CC(<quit>,<PUSHJ P,.QUIT>)
	CC(<run>,<PUSHJ P,.RUN>)
	CC(<socket.map>,<PUSHJ P,.SMAP>)
	CC(<netstatus>,<PUSHJ P,.NSTS>)
	CC(<help>,<PUSHJ P,.HELP>)
	CC(<clear.output.character=>,<PUSHJ P,SETCBF>)
	CC(<escape.character=>,<PUSHJ P,SETESC>)
	XWD -1,YNTB
	CC(<current.modes.are>,<PUSHJ P,PRCMD>)
	CC(<no>,<JRST [SETCA NOA,
			MOVE TAB,YNTB
			JRST SYMVAN]>)
	CC(<remote.mode>,<PUSHJ P,SETREM>)
	CC(<local.mode>,<TRZ F,REMOTF>)
	CC(<terminal.type.is>,<PUSHJ P,SETTRM>)
	CC(<echo.mode.is>,<PUSHJ P,.ECHO>)
	CC(<news>,<PUSHJ P,.NEWS>)
	CC(<status.of>,<PUSHJ P,.STAT>)
	CC(<disconnect>,<PUSHJ P,.DISC>)
	CC(<connection.to>,<PUSHJ P,.CONN>)
COMTAB:	XWD TOPC-.,TOPC
YNT:	CC(<signal.waiting.output>,<MOVEM NOA,SWOFLG>)
	CC(<typescript.to.file>,<PUSHJ P,SETSCR>)
	CC(<divert.output.stream.to.file>,<PUSHJ P,SETDIV>)
	CC(<fancy.command.interpret>,<SETCAM NOA,NFANCY>)
	CC(<verbose>,<SETCAM NOA,CONCSF>)
	CC(<concise>,<MOVEM NOA,CONCSF>)
	CC(<attention.character:>,<PUSHJ P,SETATN>)
	CC(<synch.character:>,<PUSHJ P,SETSNC>)
	CC(<quote.prefix:>,<PUSHJ P,SETQOT>)
	CC(<unshift.prefix:>,<PUSHJ P,SETUNS>)
	CC(<case.shift.prefix.for>,<PUSHJ P,SETSHF>)
	CC(<transparent.mode>,<MOVEM NOA,XPARNT(CNX)>)
	CC(<lower>,<MOVEM NOA,LOWERF(CNX)>)
	CC(<raise>,<MOVEM NOA,RAISEF(CNX)>)
	CC(<line.buffer>,<MOVEM NOA,LNBFF(CNX)>)
	CC(<character.mode>,<SETCAM NOA,LNBFF(CNX)>)
YNTB:	XWD YNT-.,YNT

; Null table

NTP:	CC(<>,<JFCL>)
NULTAB:	XWD NTP-.,NTP

; Table of character code specifiers

CDTB:	CC(<d%d*%d>,<PUSHJ P,SNDDCD>)
	CC(<h%h*%h>,<PUSHJ P,SNDHCD>)
	CC(<o%o*%o>,<PUSHJ P,SNDOCD>)
	CC(<%o*%o>,<PUSHJ P,SNDOCT>)
CODTB:	XWD CDTB-.,CDTB

; Command table for terminal modes

TRMT:	CC(<lowercase>,<PUSHJ P,SETLWR>)
	CC(<halfduplex>,<MOVEM NOA,HDX>)
	CC(<fullduplex>,<SETCAM NOA,HDX>)
	CC(<no>,<JRST [	SETCA NOA,
			JRST SYMVAN]>)
TRMTAB:	XWD TRMT-.,TRMT
; Command table for echo modes

ETP:	CC(<local>,<JRST [	MOVEM NOA,ELCLF(CNX)
				JRST CHGECH]>)
	CC(<remote>,<JRST [	SETCAM NOA,ELCLF(CNX)
				JRST CHGECH]>)
	CC(<linefeed.for.carriage.return>,<MOVEM NOA,LFCRF(CNX)>)
	CC(<control.character.echo.for>,<PUSHJ P,SETCOC>)
	CC(<no>,<JRST [SETCA NOA,
			JRST SYMVAN]>)
ECTAB:	XWD ETP-.,ETP

; Command table for socket lookup

STP:	CC(<FTP>,<PUSHJ P,.STFSK
			3>)
	CC(<RJS>,<PUSHJ P,.STFSK
			5>)
	CC(<Terminal.test>,<PUSHJ P,.STFSK
			23>)
	CC(<Netstatus>,<PUSHJ P,.STFSK
			17>)
	CC(<Date>,<PUSHJ P,.STFSK
			15>)
	CC(<Systat>,<PUSHJ P,.STFSK
			13>)
	CC(<Discard>,<PUSHJ P,.STFSK
			11>)
	CC(<Echo>,<PUSHJ P,.STFSK
		7>)
	CC(<logger>,<PUSHJ P,.STFSK
			1>)
	CC(<%o*%o>,<PUSHJ P,OCTFSK>)
	CC(<name.for.connection.is>,<PUSHJ P,.STNAM>)
	XWD -1,SETTAB
	XWD -1,NULTAB
SKTTAB:	XWD STP-.,STP

STB:	CC(<no>,<JRST [	SETCA NOA,
			MOVE TAB,SETTAB
			JRST SYMVAN]>)
	CC(<wait>,<MOVEM NOA,WATFLG>)
	CC(<load.settings>,<MOVEM NOA,LODFLG>)
SETTAB:	XWD STB-.,STB

; Host table

HTP:	XWD -1,NHSTAB
	XWD -1,SHSTAB
	XWD -1,OCTB
HOSTAB:	XWD HTP-.,HTP

; Octal number table

OCT:	CC(<%o*%o>,<PUSHJ P,CVOCT>)
OCTB:	XWD OCT-.,OCT

; Decimal number table

DCM:	CC(<%d*%d>,<PUSHJ P,CVDEC>)
DCMTB:	XWD DCM-.,DCM

; Letter table

LTR:	CC(<%a>,<ILDB A,BPTR>)
LTRTB:	XWD LTR-.,LTR
; Connection name table

NAMT:	CC(<%n*%n>,<SETO A,>)
NAMTB:	XWD -2,[XWD NAMT-.,NAMT
		XWD -1,CONTAB]

; Case shift command table

SFTAB:	CC(<lock.upper.case>,<MOVEI A,UCASL>)
	CC(<char.upper.case>,<MOVEI A,UCASC>)
	CC(<lock.lower.case>,<MOVEI A,LCASL>)
	CC(<char.lower.case>,<MOVEI A,LCASC>)
SFTB:	XWD SFTAB-.,SFTAB

; Socket map host table

SMTAB:	XWD -1,HOSTAB
	CC(<all>,<SETOB C,A>)
SMTB:	XWD SMTAB-.,SMTAB

; Socket map state table

STTAB:	Q←←0
	FOR STAT IN (dead,clzd,pndg,lsng,rfcr,clw2,rfcs,opnd,clsw,datw,rfn1,clzw,rfn2,kild)<
	CC(<STAT>,<	IFL Q-=18,<MOVSI A,1⊗<=17-Q>>
			IFG Q-=17,<MOVEI A,1<=35-Q>>>)
Q←←Q+1>
Q←←Q+1>
	CC(<all>,<SETO A,>)
STTB:	XWD STTAB-.,STTAB
; Symbol evaluator

SYMVAL:	SETO NOA,
SYMVAN:	MOVEM PTR,BPTR		; Save beginning of symbol
SYMLUP:	PUSHJ P,GCH		; Get a character
	CAIE A,"A"-100		; Control-A
	 CAIN A,"H"-100		; Or control-h
	  JRST DELCH		; Delete character
	CAIN A,"R"-100
	 JRST RETYPE		; Control-R, retype line
	CAIN A,"W"-100		; Control-W
	 JRST DELWRD		; Delete word
	CAIN A,"?"		; Question mark
	 JRST PRQUES		; Print options
	CAIE A,33		; Altmode or
	 CAIN A,37		; Eol
	  JRST SYMEND		; Lookup
	CAIE A,","		; Comma
	 CAIN A," "		; Or space same thing
	  JRST SYMEND
	IDPB A,PTR		; Else deposit into string
	PUSHJ P,TRMST
	SKIPE NFANCY
	 JRST SYMLPE
	SETZ X,			; Clear X
	MOVEM P,SVP		; Save P
	MOVE Y,TAB		; Init Y
	PUSHJ P,SYMLUK		; Lookup the current symbol
	MOVE P,SVP		; Restore p
	JUMPE X,[	DPB X,PTR; Smash null onto last character
			MOVE A,PTR
			BKJFN	; Back up pointer
			 JRST 4,.
			MOVEM A,PTR
			JRST DING]; And echo bell
SYMLPE:	LDB A,PTR		; Symbol still ok, get char
	PUSHJ P,ECHOIT
	JRST SYMLUP		; And loop
DELCH:	CAMN PTR,BPTR		; Delete character, any to delete?
	 JRST DING		; No, echo bell
	MOVEI A,"\"
	PUSHJ P,.PBOUT
	LDB A,PTR
	PUSHJ P,.PBOUT
	MOVE A,PTR
	BKJFN
	 JRST 4,.-1
	MOVEM A,PTR
	JRST SYMLUP

TRMST:	PUSH P,A
	PUSH P,PTR
	SETZ A,
	IDPB A,PTR
	POP P,PTR
	POP P,A
	POPJ P,

DING:	MOVEI A,7
	PUSHJ P,.PBOUT
	JRST SYMLUP

DELWRD:	CAMN PTR,BPTR		; Delete word
	 JRST DING		; Nothing
	MOVEI A,"#"
	PUSHJ P,.PBOUT
	PUSHJ P,.PBOUT
DELW0:	MOVE PTR,BPTR
	JRST SYMLUP

RETYPE:	MOVE A,PTR
	MOVEI B,0
	IDPB B,A
	MOVEI A,37
	PUSHJ P,.PBOUT
	MOVE A,LPTR
	PUSHJ P,.PSOUT
	JRST SYMLUP
; End of symbol, try lookup

SYMEND:	MOVEM A,TERM		; Save terminator
	PUSHJ P,TRMST
	SETZ X,
	MOVE Y,TAB
	PUSHJ P,SYMLUK
	JUMPE X,[	HRROI A,[ASCIZ / ? /]
			PUSHJ P,ERROUT
			MOVE A,TERM
			CAIE A,37
			 JRST DELW0
			JRST COMLP]
	CAIE X,1		; Exactly one symbol
	 JRST SYMAMB		; No. ambiguous
	POP P,C			; Leave pointer to head in c
	POP P,B			; Get pointer to tail of command
SYMCLP:	ILDB A,B		; Copy to terminal
	JUMPE A,SYMECL
	MOVE D,TERM
	SKIPE HDX
	 JRST NCOMP
	SKIPN NFANCY
	 SKIPE CONCSF
NCOMP:	  CAIN D,33
	   PUSHJ P,.PBOUT
	IDPB A,PTR
	JRST SYMCLP

SYMECL:	MOVEI A,40
	MOVE D,TERM
	CAIN D,33
	 JRST [	PUSHJ P,.PBOUT
		JRST SYMEC1]
	CAIE D,37
	 MOVE A,D
	PUSHJ P,ECHOIT
SYMEC1:	IDPB A,PTR
	PUSHJ P,TRMST
	XCT 1(B)		; Execute "value"
	POPJ P,			; And return
	XCT 2(B)		; If first value skips, execute 2nd
	POPJ P,

SYMAMB:	JUMPE X,DING		; Nothing left, go ding
	POP P,C			; Leave pointer to head in c
	POP P,B			; Get pointer to tail
	ILDB A,B		; Get first ch of tail
	JUMPN A,[SOJA X,SYMAMB]	; If not null, then loop
SYMAML:	SOJLE X,SYMECL		; Else unique
	SUB P,[XWD 2,2]		; Flush the junk
	JRST SYMAML
PRQUES:	PUSHJ P,ECHOIT
	PUSHJ P,TRMST
	SETZ X,
	MOVE Y,TAB
	PUSHJ P,SYMLUK		; Get all the possibilities
PRQUEL:	JUMPE X,RETYPE		; All done, retype the line
	MOVEI A,37
	PUSHJ P,.PBOUT		; Eol
	TRZ F,TMPF!TMPF2
PRQUEN:	ILDB A,0(P)
	JUMPE A,PRQUEE
	CAIN A,"*"
	 JRST [	HRROI A,[ASCIZ /<any number of /]
		PUSHJ P,.PSOUT
		TRO F,TMPF
		JRST PRQUEN]
	CAIN A,"%"
	 JRST [	ILDB A,0(P)
		CAIN A,"%"
		 JRST .+1
		SETZ B,
		CAIN A,"d"
		 HRROI B,[ASCIZ /decimal digit/]
		CAIN A,"o"
		 HRROI B,[ASCIZ /octal digit/]
		CAIN A,"h"
		 HRROI B,[ASCIZ /hexadecimal digit/]
		CAIN A,"a"
		 HRROI B,[ASCIZ /alphabetic/]
		CAIN A,"n"
		 HRROI B,[ASCIZ /alphameric/]
		CAIN A,"s"
		 HRROI B,[ASCIZ /separator/]
		CAIN A,"p"
		 HRROI B,[ASCIZ /punctuation mark/]
		CAIN A,"x"
		 HRROI B,[ASCIZ /any character/]
		JUMPE B,.+1
		MOVEI A,"<"
		TRNN F,TMPF
		 PUSHJ P,.PBOUT
		MOVE A,B
		PUSHJ P,.PSOUT
		TRO F,TMPF2
		JRST PRQUEQ]
	PUSHJ P,.PBOUT
PRQUEQ:	TRNN F,TMPF!TMPF2
	 JRST PRQUEN
	HRROI A,[ASCIZ /'s>/]
	TRZE F,TMPF2
	 HRROI A,[ASCIZ /s>/]
	TRZN F,TMPF
	 HRROI A,[ASCIZ />/]
	PUSHJ P,.PSOUT
	JRST PRQUEN

PRQUEE:	SUB P,[XWD 2,2]		; Flush pointer to end
	SOJA X,PRQUEL		; And loop
; Lookup symbol
; Operates recursively and accumulates a list of things on the stack

SYMLUK:	PUSH P,SVP		; Save old bottom
	MOVEM P,SVP		; Svp points to chain of svp
	TLNE Y,7000		; Byte pointer in y?
	 JRST SYMLK1		; No aobjn word
	PUSH P,Y		; Yes, sve y
	MOVE D,BPTR		; Get pointer to symbol
SYMLKL:	ILDB A,D		; Get character from input
	ILDB B,Y		; And from table entry
	PUSHJ P,SYMCMP		; Compare the characters
	 JRST SYMNEQ		; Not equal
	JUMPN A,SYMLKL		; Continue until null
SYMEQL:	MOVE A,Y
	BKJFN			; Back up pointer to tail
	 JRST [	CAIE A,600150	; Don't bomb out if empty list--
		 JRST 4,.	; (non-negative AOBJN pointer)
		JRST SYMNEX]
	MOVEM A,Y
	EXCH Y,-2(P)		; Pointer to tail to stack, get ret
	POP P,A			; Pointer to head
	POP P,SVP		; Restore svp
	PUSH P,A		; Pointer to head back to stack
	AOJA X,0(Y)		; Return and count items

SYMNEQ:	JUMPE A,SYMEQL		; If input ends first, then substring
SYMNEX:	SUB P,[XWD 1,1]		; Else flush saved y
	POP P,SVP		; Restore svp
	POPJ P,			; And return

SYMLK1:	PUSH P,Z		; Save z
	MOVE Z,Y		; Use as place to count y
SYMLK3:	MOVE Y,0(Z)		; Loop to here for each item
	PUSHJ P,SYMLUK		; Do this item
	AOBJN Z,SYMLK3		; Loop over all things
	MOVE A,P		; Get p
	SUB A,[XWD 1,1]
	CAMN A,SVP		; Any items saved on stack?
	 JRST SYMLK4		; No, shuffle not needed
	MOVE A,SVP		; Get base of stack
	MOVE Z,1(A)		; Restore z
	POP A,SVP		; Restore svp
	MOVE Y,0(A)		; Get return
	MOVEI B,0(A)		; Where to blt to
	HRLI B,3(A)		; And where from
	BLT B,-3(P)		; Copy stack down
	SUB P,[XWD 3,3]
	JRST 0(Y)		; Return

SYMLK4:	POP P,Z
	POP P,SVP
	POPJ P,
SYMCMP:	CAIN B,"*"		; Asterisk
	 JRST SYMMNY		; Means any number of
	CAIN B,"%"		; Percent
	 JRST SYMCLS		; Means character class
	CAIN B,"#"		; Pound sign
	 JRST SYMNCL		; Means not character class
SYMCM2:	PUSH P,B
	PUSH P,A
	XOR A,B
	TRZ B,40		; Ignore case of B
	CAIL B,"A"		; Then if B has
	 CAILE B,"Z"		;  a letter
	  CAIA
	   TRZ A,40		; Then ignore case of difference
	SKIPN A
	 AOS -2(P)
	POP P,A
	POP P,B
	POPJ P,

SYMMNY:	PUSH P,Y		; Save where we are in table entry
	ILDB B,Y		; Get what we are doing many of
	PUSHJ P,SYMCMP		; Check match
	 JRST SYMMNN		; Not equal
	ILDB B,Y		; See if next is also equal
	PUSHJ P,SYMCMP
	 JRST [	EXCH A,0(P)	; Not equal, get back y, save a
		BKJFN
		 JRST 4,.
		MOVEM A,Y
		POP P,A
		JRST SKPRET]
	SUB P,[XWD 1,1]		; Matches next thing, use it instead
SKPRET:	AOS (P)
	POPJ P,

SYMMNN:	SUB P,[XWD 1,1]		; Go to next thiing
	ILDB B,Y
	JRST SYMCMP
SYMCLS: ILDB B,Y		; Get class indicator
	CAIN B,"%"		; %% means %
	 JRST SYMCM2
	CAIN B,"d"		; d means decimal digit
	 JRST SYMDEC
	CAIN B,"o"		; o means octal digit
	 JRST SYMOCT
	CAIN B,"h"
	 JRST SYMHEX
	CAIN B,"a"		; a means alphabetic
	 JRST SYMALP
	CAIN B,"n"		; n means alphameric
	 JRST SYMALM
	CAIN B,"s"		; s means separator
	 JRST SYMSEP
	CAIN B,"p"		; p for punctuation
	 JRST SYMPNC
	CAIN B,"x"
	 JRST SYMANY
	POPJ P,			; Else fail
SYMNCL:	PUSHJ P,SYMCLS
	 AOS (P)
	POPJ P,

SYMANY:	AOS (P)
	POPJ P,

SYMDEC:	CAIG A,"9"
	 CAIGE A,"0"
	  POPJ P,
	JRST SKPRET

SYMOCT:	CAIG A,"7"
	 CAIGE A,"0"
	  POPJ P,
	JRST SKPRET

SYMHEX:	CAIG A,"9"
	 CAIGE A,"0"
	  JRST SYMHE1
	JRST SKPRET

SYMHE1:	TRZ A,40
	CAIG A,"F"
	 CAIGE A,"A"
	  POPJ P,
	JRST SKPRET

SYMALM:	PUSHJ P,SYMDEC
	 JRST SYMALP
	JRST SKPRET

SYMALP:	TRZ A,40
	CAIG A,"Z"
	 CAIGE A,"A"
	  POPJ P,
	JRST SKPRET

SYMSEP:
SYMPNC:	POPJ P,
; News

.NEWS:	MOVEI B,367
	MOVEM B,FSKT
	MOVEI A,361
	MOVEM A,FHSTN
	MOVEM A,FHST
	JRST CONNX1

; Connect.to

.CONN:	MOVE TAB,HOSTAB
	PUSHJ P,SYMVAL
	MOVEM A,FHSTN
CONNX:	MOVEM A,FHST
	SETOM FSKT
CONNX1:	MOVSI X,-NCONN
	SKIPE SNDJFN(X)
	 AOBJN X,.-1
	JUMPGE X,[ERROR [ASCIZ /too many connections./]]
	HRRZS NCNX,X
	MOVE A,NCNX
	IMULI A,3
	ADDI A,CONNAM
	HRLI A,440700
	MOVEI B,1(X)
	MOVEI C,010
	NOUT
	 JFCL
	IBP A
	HRLI X,(<MOVEI A,0>)
	MOVEM X,1(A)
	SKIPL FSKT
	 JRST CONN2
	PUSHJ P,DEFSKT
	PUSHJ P,SETMOD
	 JRST CONN2		; Settings not changed
	HRROI A,[ASCIZ /(settings loaded) /]
	SKIPN CONCSF
	 PUSHJ P,.PSOUT
;	JRST CONN2
CONN2:	HRROI A,[ASCIZ /is /]
	PUSHJ P,.PSOUT
	PUSHJ P,ASNSKT
	PUSHJ P,DOICP		; Do icp
	 JRST [	SKIPN WATFLG	; Failed. wait?
		 JRST CONFL	; No.
		HRROI A,[ASCIZ /incomplete on first try.
Trying again ... /]
		SKIPG WATFLG
		 PUSHJ P,.PSOUT
		MOVMS WATFLG
		MOVEI A,=10000
		DISMS
		JRST .-2]
	MOVEI A,7
	MOVEI B,20
	SKIPLE WATFLG
	 PUSHJ P,.PBOUT
	SOJG B,.-2
	HRROI A,[ASCIZ /complete/]
	PUSHJ P,.PSOUT
	MOVEI A,400000
	DIR
	SKIPE A,SNDFRK(NCNX)
	 JRST CONN3
	MOVSI A,(1B1)
	CFORK
	 JRST [	JSP X,CONFL0
		ASCIZ /can't create send fork./]
	MOVEM A,SNDFRK(NCNX)
	PUSHJ P,MAPFRK
CONN3:	PUSHJ P,INIFRK
	SKIPE A,RCVFRK(NCNX)
	 JRST CONN4
	MOVSI A,(1B1)
	CFORK
	 JRST [	JSP X,CONFL1
		ASCIZ /can't create receive fork./]
	MOVEM A,RCVFRK(NCNX)
	PUSHJ P,MAPFRK
CONN4:	PUSHJ P,INIFRK
	MOVE A,IJFN
	MOVEM A,SNDJFN(NCNX)
	MOVE A,JJFN
	MOVEM A,RCVJFN(NCNX)
	SETZM IJFN
	SETZM JJFN
	MOVE CNX,NCNX
	HLRE A,CONTAB
	MOVNS A
	ADD A,CONTAB
	HRRZ B,CNX
	IMULI B,3
	ADDI B,CONNAM
	HRLI B,440700
	MOVEM B,(A)
	MOVSI B,-1
	ADDM B,CONTAB
	MOVN A,LSKT(CNX)
	ASH A,-1
	MOVSI B,(1B0)
	ROT B,(A)
	IORM B,SKTMSK
	SETZM SAVSWT(CNX)
	MOVEI B,SEND
	MOVE A,SNDFRK(CNX)
	FFORK
	SFORK
	MOVE A,RCVFRK(CNX)
	MOVEI B,RECV
	FFORK
	SFORK
	TRO F,REMOTF
	MOVEI A,400000
	EIR
	MOVEI A,"."
	PUSHJ P,.PBOUT
	POPJ P,
CONFL1:CONFL0:	HRROI A,[ASCIZ /,
 but /]
	PUSHJ P,.PSOUT
	PUSHJ P,RELCON
	JRST CONFLX

CONFL:	PUSH P,A
	HRROI A,[ASCIZ /incomplete,
 because /]
	PUSHJ P,.PSOUT
	POP P,A
CONFLX:	PUSHJ P,.PSOUT
	POPJ P,

; Assign socket for connection

ASNSKT:	SETCM A,SKTMSK
	PUSH P,B
	JFFO A,ASNSK1
	MOVEI B,177
ASNSK1:	MOVE A,B
	POP P,B
	LSH A,1
	POPJ P,
; Perform icp

DOICP:	MOVEM A,LSKT(NCNX)	; Remember local socket
	MOVE A,PTR
	IBP A			; Use area past command string
	PUSH P,A		; Save start of string
	HRROI B,[ASCIZ /NET:/]
	SETZ C,
	SOUT
	PUSH P,A		; Save where socket number is
	MOVE B,LSKT(NCNX)
	MOVE C,[1B2+1B3+3B17+10]
	NOUT
	 JRST 4,.-1
	MOVEI B,"."
	IDPB B,A
	SETZ C,
	MOVE B,FHST
	TLNE B,-1		; Number ?
	 JRST [	SOUT		; No, string, use it
		JRST ICP9]
	MOVEI C,10
	NOUT
	 JRST 4,.-1
ICP9:	MOVEI B,"-"
	IDPB B,A
	PUSH P,A		; Save where fs begins
	MOVE B,FSKT
	MOVEI C,10
	NOUT
	 JRST 4,.-1
	HRROI B,[ASCIZ /;T/]
	SETZ C,
	SOUT
;	JRST ICPA
ICPA:	MOVE B,-2(P)		; Get beginning of string
	MOVEI A,400000
	DIR
	MOVSI A,1		; Short form, string pointer
	GTJFN
	 JRST [	JSP X,ICPFL2
		ASCIZ /IMP is disconnected./]
	MOVEM A,IJFN		; Save jfn to be released if int
	MOVEI A,400000
	EIR			; Interrupts 
	TIME
	MOVEM A,ICPTIM
	MOVE A,IJFN
	MOVE B,[XWD 400001,200000]
	PUSHJ P,.OPENF
	 JRST [	PUSHJ P,HSTCHK
		 JRST [	JSP X,ICPFL2
			ASCIZ /host is disconnected./]
		JSP X,ICPFL2
		ASCIZ /host is rejecting./]
	MOVE A,IJFN
	BIN			; Get socket number to use
	MOVEI A,400000
	DIR
	MOVE A,IJFN
	CLOSF
	 JFCL
	SETZM IJFN
	MOVEI A,400000
	EIR
	POP P,A			; Back to beginning of fs
	MOVEI C,10
	NOUT
	 JRST 4,.-1
	HRROI B,[ASCIZ /;T/]
	SETZ C,
	SOUT
	POP P,A			; Get loc of ls
	MOVE B,LSKT(NCNX)
	ADDI B,2
	MOVE C,[1B2+1B3+3B17+10]
	NOUT
	 JRST 4,.-1
	MOVEI B,"."
	IDPB B,A
;	JRST ICPB
ICPB:	MOVE B,0(P)		; Beginning of string
	MOVEI A,400000
	DIR
	MOVSI A,1
	GTJFN
	 JRST [	JSP X,ICPFL1
		ASCIZ /no send JFN/]
	MOVEM A,IJFN
	POP P,B
	MOVSI A,1
	GTJFN
	 JRST [	JSP X,ICPFL0
		ASCIZ /no recv JFN/]
	MOVEM A,JJFN
	MOVEI A,400000
	EIR
	MOVE A,IJFN
	MOVE B,[XWD 103402,100000]
	OPENF			; Open send, don't wait
	 JRST [	JSP X,ICPFL0
		ASCIZ /send connection can't be opened./]
	MOVE A,JJFN
	MOVE B,[XWD 100010,200000]
	PUSHJ P,.OPENF
	 JRST [	JSP X,ICPFL0
		ASCIZ /receive connection can't be opened./]
	MOVE A,IJFN
	PUSHJ P,OPNWAT		; Wait for connection to be opened
	 JRST [	JSP X,ICPFL0
		ASCIZ /send connection was not successfully opened./]
	TIME
	SUBM A,ICPTIM
	AOS (P)
	POPJ P,
ICPFL2:	SUB P,[XWD 2,2]
ICPFL1:	SUB P,[XWD 1,1]
ICPFL0:	SETOM ICPTIM
	PUSHJ P,RELCON
	HRROI A,(X)
	POPJ P,

RELCON:	MOVEI A,400000
	DIR
	SKIPE A,IJFN
	 PUSHJ P,CLRJFN
	SKIPE A,JJFN
	 PUSHJ P,CLRJFN
	SETZM IJFN
	SETZM JJFN
	MOVEI A,400000
	EIR
	POPJ P,
OPNWAT:	PUSH P,A
	JRST OPNWT0

.OPENF:	PUSH P,A
	TLO B,3000
	OPENF
	 JRST OPNFL1
OPNWT0:	SETOM NTICNT
	MOVEI B,24
	MOVSI C,777700+NTICHN
	MTOPR			; Cause fsm state changes to interrupt
OPNWTL:	SETOM NTICNT
	MOVE A,0(P)
	GDSTS
	ROT B,4
	ANDI B,17
	CAIN B,7
	 JRST OPNWIN
	CAIE B,6
	 JRST OPNFL
	MOVEI A,=100000
	AOSN NTICNT		; Increment to 0 if waiting
OPNWTK:	 DISMS
	JRST OPNWTL

OPNWIN:	POP P,A
	MOVEI B,24
	SETO C,
	MTOPR
	JRST SKPRET

OPNFL1:	POP P,A
	POPJ P,

OPNFL:	POP P,A
	CLOSF
	 JFCL
	POPJ P,

NTIINT:	MOVEM A,NTIIA
	AOSN NTICNT
	DEBRK
	HRRZ A,RETPC3
	CAIE A,OPNWTK
	 CAIN A,OPNWTK+1		; Either two locations is ok
	  SKIPA A,[XWD 10000,OPNWTL]
	   SKIPA A,NTIIA
	MOVEM A,RETPC3
	DEBRK
; Disconnect

.DISC:	MOVE A,TERM
	MOVE X,CNX
	CAIN A,37
	 JRST DISC1
	SKIPL TAB,CONTAB
	 POPJ P,
	PUSHJ P,SYMVAL
	MOVE X,A
DISC1:	MOVEI A,400000
	DIR
	CAMN X,CNX
	 TRZ F,REMOTF
	MOVE A,ABNCNX		; Might be abncnx
	SETOM ABNCNX		; Clear it
	CAMN X,A		; And if it was
	 SETOM ABNLCK		; Unlock abnlck
	SKIPN RCVJFN(X)
	 POPJ P,		; No connection
	MOVE A,RCVFRK(X)
	FFORK
	SKIPE A,RCVJFN(X)
	 PUSHJ P,CLRJFN
	SKIPE A,SNDJFN(X)
	 PUSHJ P,CLRJFN
	SETZM RCVJFN(X)
	SETZM SNDJFN(X)
	MOVN A,LSKT(X)
	ASH A,-1
	MOVSI B,(1B0)
	ROT B,(A)
	ANDCAM B,SKTMSK
	IMULI X,3		; Compute pointer to this name
	ADDI X,CONNAM
	HRLI X,440700
	MOVE Y,CONTAB
	CAME X,0(Y)		; Search for entry in contb
	 AOBJN Y,.-1
	MOVE A,1(Y)		; Move entries above here, down to
	MOVEM A,0(Y)		;  fill in the gap
	AOBJN Y,.-2
	MOVSI X,1
	ADDM X,CONTAB		; One less entry in contb
	MOVEI A,400000
	EIR
	POPJ P,
; Set name for connection

.STNAM:	MOVE TAB,NAMTB
	PUSHJ P,SYMVAL
	JUMPGE A,NAMINU
	HRRZ A,NCNX
	IMULI A,3
	ADDI A,CONNAM
	HRLI A,440700
	MOVE B,BPTR
	MOVEI C,=8
	LDB D,PTR		; Get terminator
	SOUT			; Copy through it
	SETZ B,
	DPB B,A			; Replace terminator with null
	MOVE B,NCNX
	HRLI B,(<MOVEI A,>)
	MOVEM B,1(A)
	POPJ P,

NAMINU:	ERROR [ASCIZ /name already in use/]

; Wait for a connection wanting to print

WATRET:	MOVSI X,-NCONN
WATREL:	SKIPG SNDJFN(X)
	 JRST WATREX
	SKIPG SAVINC(X)
	 JRST WATREX
	HRROI A,[ASCIZ /
connection /]
	PUSHJ P,.PSOUT
	HRRZ A,X
	IMULI A,3
	HRROI A,CONNAM(A)
	PUSHJ P,.PSOUT
	HRROI A,[ASCIZ / ready. /]
	PUSHJ P,.PSOUT
	HRRZ A,X
	JRST RETCO1

WATREX:	AOBJN X,WATREL
	MOVEI A,=10000
	DISMS
	JRST WATRET

; Retrieve connection

RETCON:	SKIPL TAB,CONTAB
	 JRST [	HRROI A,[ASCIZ /
No connections.
/]
		PUSHJ P,.PSOUT
		POPJ P,]
	PUSHJ P,SYMVAL
RETCO1:	MOVEM A,CNX
	TRO F,REMOTF
	POPJ P,
; List connections

LSTCON:	TRZ F,TMPF
	MOVE X,CONTAB
	JUMPGE X,LSTCOX
LSTCOL:	HRROI A,[ASCIZ /
-Name-  -From-  --To--

/]
	TRON F,TMPF
	PUSHJ P,.PSOUT
	SETZ C,
	MOVE A,(X)
	PUSHJ P,.PSOUT
	MOVE B,1(A)
	MOVEI A,11
	PUSHJ P,.PBOUT
	MOVEI A,101
	MOVE B,SNDJFN(B)
	MOVE C,[BYTE (3)0,0,1,1,0,0,0(5)0,0,2]
	JFNS
	SKIPE A,SCRJFN
	 JFNS
	PUSHJ P,SCRUPD
	MOVEI A,37
	PUSHJ P,.PBOUT
LSTCOX:	AOBJN X,LSTCOL
	HRROI A,[ASCIZ /
No saved connections./]
	TRZN F,TMPF
	 PUSHJ P,.PSOUT
	POPJ P,
; Set mode switches

SETMOD:	SKIPN LODFLG
	 POPJ P,
	PUSHJ P,OPNMDF		; Open mode file
	 POPJ P,		; Non-existent
	 JFCL			; Ok if we can't write
	PUSHJ P,SCHMDF		; Search mode file for the right host
	 JRST STMDX		; Not found
	MOVE C,PMODSW
	BIN
	MOVEM B,@0(C)
	AOBJN C,.-2
	AOS (P)
STMDX:	PUSHJ P,CLRJFN
	SETZM IJFN
	POPJ P,
WRTMDF:	MOVE TAB,HOSTAB
	PUSHJ P,SYMVAL
	PUSHJ P,DEFSKT
	PUSHJ P,OPNMDF		; Open it
	 JFCL			; Can't find it
	 JRST [	HRROI A,[ASCIZ /Cannot write TELNET.MODES/]
		PUSHJ P,.PSOUT
		SKIPE A,IJFN
		 PUSHJ P,CLRJFN
		SETZM IJFN
		POPJ P,]
	PUSHJ P,SCHMDF		; See if old settings exist
	 JRST WRTMD1		; No, ok to write
	HRROI A,[ASCIZ /Confirm /]
	PUSHJ P,.PSOUT
	PUSHJ P,GCH
	CAIE A,37
	 JRST [	HRROI A,[ASCIZ /Not done./]
		PUSHJ P,.PSOUT
		JRST WRTMDX]
	MOVE A,IJFN
WRTMD1:	MOVE B,FHSTN
	ROUT
	MOVE B,FSKT
	BOUT
	MOVE NCNX,CNX
	MOVE C,PMODSW
	MOVE B,@0(C)
	BOUT
	AOBJN C,.-2
WRTMDX:	MOVE A,IJFN
	PUSHJ P,CLRJFN
	SETZM IJFN
	POPJ P,

PMODSW:	XWD -NMODSW,MODSWP

MODSWP:	FOR A IN (LFCRF,ELCLF,LNBFF,RAISEF,JUNK,ECHCOC,LOWERF,JUNK,JUNK,JUNK),
<	XWD NCNX,A
>

SCHMDF:	MOVEI C,0		; Start with word 0
SCHMDL:	RIN			; Read it
	JUMPE B,CPOPJ		; End of file
	CAME B,FHSTN		; Correct host?
	 JRST SCHMDN		; Not this, try next
	BIN			; Get socket
	CAMN B,FSKT		; Correct one?
	 JRST SKPRET
SCHMDN:	ADDI C,NMODSW+2
	JRST SCHMDL
OPNMDF:	MOVEI A,400000
	DIR
	HRROI B,[ASCIZ /<DOCUMENTATION>TELNET.MODES/]
	MOVSI A,1
	GTJFN
	 JRST [	MOVEI A,400000
		EIR
		POPJ P,]
	MOVEM A,IJFN
	MOVEI A,400000
	EIR
	MOVE A,IJFN
	MOVE B,[XWD 440000,300000]
	OPENF
	 JRST [	MOVE A,IJFN
		TRZE B,100000
		 JRST .-1
		PUSHJ P,CLRJFN
		SETZM IJFN
		POPJ P,]
	TRNE B,100000
	 AOS (P)
	JRST SKPRET
; Status.of

.STAT:	MOVEI NCNX,NCONN	; Use this cnx for status
	MOVE TAB,HOSTAB
	PUSHJ P,SYMVAL
	MOVEM A,FHST
	PUSHJ P,DEFSKT
	PUSHJ P,SETMOD
	 JFCL
STAT1:	MOVEI NCNX,NCONN	; For late-comers
	MOVEI A,74		; Local socket for icp
	PUSHJ P,DOICP
	 JRST STAT2
	PUSHJ P,RELCON		; Flush things set up by doicp
	HRROI A,[ASCIZ /logger operational./]
STAT2:	PUSHJ P,.PSOUT
	POPJ P,
; Exec

.EXEC:	HRROI B,[ASCIZ /<SYSTEM>EXEC.SAV/]
	MOVSI C,(1B0)		; CAUSE INTERRUPTS TO GO OFF
	MOVSI A,100001
	JRST SBGET

; Run

.RUN:	MOVSI A,100003
	MOVE B,[XWD 100,101]
	SETZ C,
	JRST SBGET

; Socket.map

.SMAP:	SETOM FAC
	SETOM FAC+1
	MOVE A,TERM
	CAIN A,37
	 JRST SMAPD
	MOVE TAB,SMTB
	PUSHJ P,SYMVAL
	TLNN A,-1
	 MOVE C,A
	MOVEM C,FAC+0
	MOVE A,TERM
	CAIN A,37
	 JRST SMAPD
	SETZM FAC+1
	HRROI A,[ASCIZ /(states) /]
	PUSHJ P,.PSOUT
SMAPL:	MOVE TAB,STTB
	PUSHJ P,SYMVAL
	IORM A,FAC+1
	MOVE A,TERM
	CAIN A,","
	 JRST SMAPL
SMAPD:	MOVEI C,1
	JRST NTSTSD
; Netstatus

.NSTS:	MOVEI C,0
NTSTSD:	HRROI B,[ASCIZ /<SUBSYS>NETSTAεSAV/]
	MOVSI A,100001
SBGET:	PUSH P,B
	PUSHJ P,GTJFN0
	 JRST [	POP P,A
		TLNN A,-1
		PUSHJ P,.PSOUT
		ERROR [ASCIZ / not available./]]
	SUB P,[XWD 1,1]
	MOVEI A,400000
	DIR
	MOVSI A,(1B1!1B3)
	MOVEI B,FAC
	CFORK
	 JRST [	HRROI A,[ASCIZ /No forks available./]
		JRST GETF]
	MOVEM A,SPCFRK
	HRLZ A,SPCFRK
	HRR A,IJFN
	GET
	SETZM IJFN
	MOVEI A,400000
	EIR
	JUMPGE C,SBGET4
	DIR
	MOVE A,ESCCOD
	DTI
	MOVE A,CBFCOD
	DTI
SBGET4:	PUSH P,C
	MOVEI A,100
	MOVE B,TTCOC0
	MOVE C,TTCOC1
	SFCOC
	MOVE B,TTMOD0
	SFMOD
	HRRZ B,0(P)
	MOVE A,SPCFRK
	SFRKV
	WFORK
	MOVEI A,400000
	DIR
	MOVE A,SPCFRK
	KFORK
	SETZM SPCFRK
	POP P,C
	JUMPGE C,SBGET5
	MOVEI A,ESCCHN
	HRL A,ESCCOD
	ATI
	MOVEI A,CBFCHN
	HRL A,CBFCOD
	ATI
SBGET5:	MOVEI A,400000
	EIR
	POPJ P,

GETF:	PUSH P,A
	MOVEI A,400000
	EIR
	SKIPE A,IJFN
	 PUSHJ P,CLRJFN
	SETZM IJFN
	POP P,A
	JRST .PSOUT
; Set escape character

SETESC:	PUSHJ P,SETICH
	 ESCAPE
	 ESCCOD
	 ESCCHN
	POPJ P,

SETCBF:	PUSHJ P,SETICH
	 CBFCHR
	 CBFCOD
	 CBFCHN
	POPJ P,

SETICH:	MOVE X,0(P)
	ADDI X,3
	EXCH X,0(P)
	PUSHJ P,.PBIN
	CAIN A,"?"
	 JRST PRESC
	PUSH P,A
	PUSHJ P,CVINTC
	 JRST SETED
	PUSH P,A
	MOVEI A,400000
	DIR
	POP P,A
	MOVE B,0(P)
	MOVEM B,@0(X)
	EXCH A,@1(X)
	DTI
	HRLZ A,@1(X)
	HRRI A,@2(X)
	ATI
	MOVE A,0(P)
	CAIL A,40
	 JRST SETE1
	MOVEI A,"↑"
	PUSHJ P,ECHOIT
	MOVEI A,100
	ADDM A,0(P)
SETE1:	POP P,A
	PUSHJ P,ECHOIT
	MOVEI A,400000
	EIR
	POPJ P,

SETED:	POP P,A
	MOVEI A,7
	PUSHJ P,.PBOUT
	JRST SETESC

PRESC:	HRROI A,[ASCIZ /
control-@ through control-Z
altmode
rubout
space
/]
	PUSHJ P,.PSOUT
	MOVE A,LPTR
	PUSHJ P,.PSOUT
	JRST SETESC
; Set terminal modes

SETTRM:	MOVE TAB,TRMTAB
	JRST SYMVAL

; Set attention character

SETATN:	SETOM BRKC
	JUMPGE NOA,CPOPJ
	PUSHJ P,.PBIN
	PUSHJ P,ECHOIT
	MOVEM A,BRKC
	POPJ P,

; Set synch character

SETSNC:	SETOM SYNC
	JUMPGE NOA,CPOPJ
	PUSHJ P,.PBIN
	PUSHJ P,ECHOIT
	MOVEM A,SYNC
	POPJ P,

; Set single charcter quote prefix

SETQOT:	SETOM QUOT
	JUMPGE NOA,CPOPJ
	PUSHJ P,.PBIN
	PUSHJ P,ECHOIT
	MOVEM A,QUOT
	POPJ P,

; Set unshift prefix

SETUNS:	SETOM UNSFT
	JUMPGE NOA,CPOPJ
	PUSHJ P,.PBIN
	PUSHJ P,ECHOIT
	MOVEM A,UNSFT
	POPJ P,

; Set case shift prefixes

SETSHF:	PUSH P,NOA		; Save noa
	MOVE TAB,SFTB
	PUSHJ P,SYMVAL
	POP P,NOA
	SETOM (A)		; Turn off prefix
	JUMPGE NOA,CPOPJ	; Done if "no"
	PUSH P,A
	PUSHJ P,.PBIN
	PUSHJ P,ECHOIT
	MOVEM A,@(P)
	SUB P,[XWD 1,1]
	POPJ P,
; Echo.mode.is

.ECHO:	MOVE TAB,ECTAB
	JRST SYMVAL

CHGECH:	HRROI A,[ASCIZ /
A half-duplex terminal (which I believe you have) will not work well with
remote echoing./]
	SKIPE HDX
	 SKIPE ELCLF(CNX)
	  SKIPA
	   PUSHJ P,.PSOUT
	SKIPN A,SNDJFN
	 POPJ P,
	MOVEI B,TELNEC
	SKIPN ELCLF(CNX)
	 MOVEI B,TELECH
	BOUT
	MOVEI B,21
	MTOPR
	POPJ P,

; Terminal has lower case

SETLWR:	MOVEM NOA,TRMLWC
	MOVSI B,(1B3)
	JUMPGE NOA,SETLW1
	IORM B,TTMODR
	IORB B,TTMODC
	JRST SETLW2

SETLW1:	ANDCAM B,TTMODR
	ANDCAB B,TTMODC
SETLW2:	MOVEI A,101
	STPAR
	POPJ P,

SNDSNC:	SKIPN A,SNDJFN(CNX)
	 POPJ P,
	MOVEI B,22
	MTOPR			; Send ins
	MOVEI B,TELSNC
	BOUT			; And sync character
	MOVEI B,21
	MTOPR
	POPJ P,
; Set control character echoing

SETCOC:	PUSHJ P,GCH
	CAIN A,"?"
	 JRST SETCOQ
	PUSHJ P,ECHOIT
SETCO2:	CAIN A,37
	 MOVEI A,15
	MOVEM A,TERM
	PUSHJ P,.PBIN
	PUSHJ P,ECHOIT
	EXCH A,TERM
	ANDI A,37
	MOVSI B,400000
	MOVNS A
	ROT B,(A)
	SKIPN NOA
	 ANDCAM B,ECHCOC(CNX)
	SKIPE NOA
	 IORM B,ECHCOC(CNX)
	MOVE A,TERM
	CAIE A,37
	 JRST [	CAIE A,40
		 CAIN A,","
		  JRST SETCOC
		JRST SETCO2]
	POPJ P,

SETCOQ:	HRROI A,[ASCIZ /
control characters or letter equivalents/]
	PUSHJ P,.PSOUT
	MOVE A,LPTR
	PUSHJ P,.PSOUT
	JRST SETCOC

SETCOE:	MOVEI A,7
	PUSHJ P,.PBOUT
	JRST SETCOC
; Print current modes

PRCMD:	MOVSI X,-NPMDTB
PRCMD1:	MOVEI A,37
	PUSHJ P,.PBOUT
	MOVSI C,CNX
	HLR C,PCMDTB(X)
	HRROI A,[ASCIZ /no /]
	SKIPN @C
	 PUSHJ P,.PSOUT
	HRRO A,PCMDTB(X)
	PUSHJ P,.PSOUT
	AOBJN X,PRCMD1
	HRROI A,[ASCIZ /
Special characters:
/]
	PUSHJ P,.PSOUT
	MOVSI X,-NSPECH
PCSLP:	HLRZ B,CSTAB(X)
	SKIPG (B)
	 JRST PCSLPN
	HRRO A,CSTAB(X)
	PUSHJ P,.PSOUT
	MOVEI A,11
	PUSHJ P,.PBOUT
	MOVE A,(B)
	PUSHJ P,.PBOUT
PCSLPE:	MOVEI A,37
	PUSHJ P,.PBOUT
PCSLPN:	AOBJN X,PCSLP
	SKIPE D,ECHCOC(CNX)
	 SKIPN ELCLF(CNX)
	  POPJ P,		; Done if not local echo or no coc
	HRROI A,[ASCIZ /
Local echo for control /]
	PUSHJ P,.PSOUT
PRCM2:	JFFO D,.+1
	MOVSI B,400000
	MOVN C,D+1
	ROT B,(C)
	ANDCAM B,D
	JUMPN D,PRCM1
	HRROI A,[ASCIZ /and /]
	CAME B,ECHCOC(CNX)
	 PUSHJ P,.PSOUT
PRCM1:	MOVEI A,100(D+1)
	PUSHJ P,.PBOUT
	JUMPE D,CPOPJ
	HRROI A,[ASCIZ /, /]
	PUSHJ P,.PSOUT
	JRST PRCM2
PCMDTB:	XWD RAISEF,[ASCIZ /Raise/]
	XWD LOWERF,[ASCIZ /Lower/]
	XWD ELCLF,[ASCIZ /Local echo/]
	XWD LFCRF,[ASCIZ /Echo linefeed for carriage return/]
	XWD LNBFF,[ASCIZ /Line buffer/]
NPMDTB←←.-PCMDTB

CSTAB:	XWD ESCAPE,[ASCIZ /Escape: /]
	XWD CBFCHR,[ASCIZ /Clrobf: /]
	XWD QUOT,[ASCIZ /Quote:  /]
	XWD UNSFT,[ASCIZ /Unshift:/]
	XWD LCASC,[ASCIZ /Char.lower:/]
	XWD LCASL,[ASCIZ /Lock.lower:/]
	XWD UCASC,[ASCIZ /Char.upper:/]
	XWD UCASL,[ASCIZ /Lock.upper:/]
	XWD BRKC,[ASCIZ /Break:  /]
	XWD SYNC,[ASCIZ /Synch:  /]

NSPECH←←.-CSTAB

; Help

.HELP:	MOVEI A,400000
	DIR
	HRROI B,[ASCIZ /<DOCUMENTATION>TELNET.HELP/]
	MOVSI A,100001
	GTJFN
	 JRST [	MOVEI A,400000
		EIR
		HRROI A,[ASCIZ /Help file not found./]
		JRST .PSOUT]
	MOVEM A,IJFN
	MOVEI A,400000
	EIR
	MOVE A,IJFN
	MOVE B,[XWD 70000,200000]
	OPENF
	 JRST [	MOVE A,IJFN
		PUSHJ P,CLRJFN
		SETZM IJFN
		HRROI A,[ASCIZ /Help file can't be opened./]
		JRST .PSOUT]
TYPLP:	MOVEI X,=20
TYPLP1:	MOVE A,IJFN
	MOVE B,[POINT 7,COMBUF]
	MOVEI C,200*5-3
	MOVEI D,12
	SIN
	GTSTS
	TLNE B,1000
	 JRST ETYPL
	MOVEI A,101
	MOVE B,[POINT 7,COMBUF]
	MOVEI C,200*5-3
	MOVEI D,12
	PUSHJ P,.SOUT
	SOJG X,TYPLP1
	CAIGE C,200*5-3-2
	 JRST TYPLP1
	HRROI A,[ASCIZ /
More help? /]
	PUSHJ P,.PSOUT
;	JRST TYPAL
TYPAL:	PUSHJ P,.PBIN
	CAIE A,"Y"
	 CAIN A,"y"
	  JRST TYPMO
	CAIE A,"N"
	 CAIN A,"n"
	  JRST TYPNO
	MOVEI A,7
	PUSHJ P,.PBOUT
	JRST TYPAL

TYPMO:	HRROI A,[ASCIZ /Yes
/]
	PUSHJ P,.PSOUT
	JRST TYPLP

TYPNO:	HRROI A,[ASCIZ /No
/]
	PUSHJ P,.PSOUT
	JRST ETYPX

ETYPL:	SUBI C,200*5-3
	SOUT
ETYPX:	MOVE A,IJFN
	PUSHJ P,CLRJFN
	SETZM IJFN
	POPJ P,
; Typescript to a file

SETSCR:	PUSHJ P,UGTAD
	MOVEM B,SCRTIM		; Time of last typescript entry
	SETZM SCRCNT		; Characters output since last openf
	MOVEI A,400000
	DIR
	SETZ A,
	EXCH A,SCRJFN
	SKIPLE A
	 PUSHJ P,CLRJFN
	JUMPGE NOA,[MOVSI A,400001
		HRROI B,[ASCIZ /TELNET.TYPESCRIPT;T/]
		GTJFN
		 JRST [	MOVEI A,400000
			EIR
			POPJ P,]
		PUSH P,A
		MOVE B,[XWD 70000,20000]
		OPENF
		 JRST [	POP P,A
			RLJFN
			 JFCL
			MOVEI A,400000
			EIR
			POPJ P,]
		HRROI B,[ASCIZ /
TELNET typescript file started at /]
		SETZ C,
		SOUT
		SETO B,
		MOVE C,[1B1+1B7+1B12+1B17]
		ODTIM
		MOVEI B,37
		BOUT
		POP P,SCRJFN
		MOVEI A,400000
		EIR
		POPJ P,]
	MOVEI A,400000
	EIR
	MOVSI A,460003
	PUSHJ P,.GTJFN
	 ERROR [ASCIZ /File not available./]
	MOVE B,[XWD 70000,100000]
	OPENF
	 JRST [	MOVE A,IJFN
		PUSHJ P,CLRJFN
		SETZM IJFN
		ERROR [ASCIZ /Cannot open file./]]
	MOVEI A,400000
	DIR
	MOVEI B,0
	EXCH B,IJFN
	MOVEM B,SCRJFN
	EIR
	POPJ P,
; Get uniform time in secs

UGTAD:	GTAD
	HRRZS B,A
	HLRZS A
	IMULI A,=24*=60*=60
	ADDB A,B
	POPJ P,

; Update script file

SCRUPD:	SKIPN SCRJFN
	 POPJ P,
	PUSH P,A
	PUSH P,B
	SKIPGE SCRTIM
	 JRST SCRUP0		; Forced update
	PUSHJ P,UGTAD
	SUB B,SCRTIM		; Ho long since last update?
	CAIG B,=30
	 JRST SCRUPX		; Never less than 30 secs
	CAIL B,=300
	 JRST SCRUP0		; Always every 5 min
	MOVE A,SCRJFN
	RFPTR
	 SETZ B,
	SUB B,SCRCNT
	CAIG B,=1000
	 JRST SCRUPX		; Then not fewer thant 1000 chars
SCRUP0:	PUSHJ P,UGTAD
	MOVEM B,SCRTIM
	MOVE A,SCRJFN
	RFPTR
	 SETZ B,
	MOVEM B,SCRCNT
	HRLI A,400000
	CLOSF
	 JFCL
	HRRZS A
	MOVE B,[XWD 70000,20000]
	OPENF
	 JRST 4,.-1
SCRUPX:	POP P,B
	POP P,A
	POPJ P,
; Divert output to a file

SETDIV:	MOVEI A,400000
	DIR
	MOVEI A,0
	EXCH A,DIVJFN
	SKIPLE A
	 PUSHJ P,CLRJFN
	MOVEI A,400000
	EIR
	JUMPGE NOA,CPOPJ
	MOVSI A,460003
	PUSHJ P,.GTJFN
	 ERROR [ASCIZ /File not found./]
	MOVE B,[XWD 70000,100000]
	OPENF
	 JRST [	MOVE A,IJFN
		PUSHJ P,CLRJFN
		SETZM IJFN
		ERROR [ASCIZ /Cannot open./]]
	MOVEI A,400000
	DIR
	MOVEI B,0
	EXCH B,IJFN
	MOVEM B,DIVJFN
	EIR
	POPJ P,
; Print where we are

.WHERE:	MOVEI A,37
	PUSHJ P,.PBOUT
	SKIPN SNDJFN(CNX)
	 JRST NOCC
	HRROI A,[ASCIZ /Connection /]
	PUSHJ P,.PSOUT
	MOVE A,CNX
	IMULI A,3
	ADDI A,CONNAM
	HRROS A
	PUSHJ P,.PSOUT
	HRROI A,[ASCIZ / from /]
	PUSHJ P,.PSOUT
	MOVEI A,101
	MOVE B,SNDJFN(CNX)
	MOVSI C,(<BYTE (3)0,0,1>)
	JFNS
	SKIPE A,SCRJFN
	 JFNS
	HRROI A,[ASCIZ / to /]
	PUSHJ P,.PSOUT
	MOVEI A,101
	MOVE B,SNDJFN(CNX)
	MOVSI 3,(<BYTE (3)0,0,0,1>)
	JFNS
	SKIPE A,SCRJFN
	 JFNS
	MOVEI A,37
	PUSHJ P,.PBOUT
NOCC:	MOVE A,[SIXBIT /SYSVER/]
	SYSGT
	MOVE D,P
	HRRZ C,B
	HLLZS B
.WHRL:	MOVE A,C
	HRL A,B
	GETAB
	 JFCL
	PUSH P,A
	AOBJN B,.WHRL
	PUSH P,[0]
	HRROI A,1(D)
	PUSHJ P,.PSOUT
	MOVE P,D
	HRROI A,[ASCIZ /
Job /]
	PUSHJ P,.PSOUT
	GJINF
	PUSH P,1
	MOVEI A,101
	MOVE B,C
	MOVEI C,12
	PUSHJ P,.NOUT
	 JFCL
;falls through
;drops in
	HRROI A,[ASCIZ /, terminal /]
	PUSHJ P,.PSOUT
	MOVE B,D
	MOVEI C,10
	MOVEI A,101
	PUSHJ P,.NOUT
	 JFCL
	HRROI A,[ASCIZ /, user /]
	PUSHJ P,.PSOUT
	POP P,B
	MOVEI A,101
	DIRST
	 JFCL
	SKIPLE A,SCRJFN
	 DIRST
	  JFCL
	HRROI A,[ASCIZ /
TELNET version /]
	PUSHJ P,.PSOUT
	HRROI A,VERNUM
	JRST .PSOUT

; Request monitor to send reset to a host
; Is nop if not wheel

.FLUSH:	MOVE TAB,HOSTAB
	PUSHJ P,SYMVAL
	TLNN A,-1
	 MOVE C,A
	PUSH P,C
	MOVEI A,400000
	DIR
	RPCAP
	EXCH C,0(P)
	PUSH P,C
	TRO C,600000
	EPCAP
	POP P,A
	FLHST
	MOVEI A,400000
	POP P,C
	EPCAP
	EIR
	POPJ P,

; Reset

.RESET:	JRST RSTART

; Logout

.LGOUT:	HRROI A,[ASCIZ / [Confirm] /]
	PUSHJ P,.PSOUT
	PUSHJ P,.PBIN
	CAIE A,37
	 POPJ P,
	PUSHJ P,.PBOUT
	MOVNI 1,1
	LGOUT
	HALTF
; Quit, exit back to exec

.QUIT:	SETOM SCRTIM
	PUSHJ P,SCRUPD		; Update script before leaving
	MOVEI A,400000
	DIR
	HALTF
	MOVEI A,-4
	FFORK
	MOVEI A,400000
	EIR
	POPJ P,

; Send code and control

SNDDCD:	IBP BPTR
	PUSHJ P,CVDEC
	JRST SNDC

SNDOCD:	IBP BPTR
SNDOCT:	PUSHJ P,CVOCT
	JRST SNDC

SNDHCD:	IBP BPTR
	SETZ A,
SNDHCL:	ILDB B,BPTR
	JUMPE B,SNDC
	CAIL B,"A"
	 ADDI B,11
	ANDI B,17
	ASH A,4
	ADD A,B
	JRST SNDHCL

SNDCTL:	MOVE TAB,LTRTB
	PUSHJ P,SYMVAL
	ANDI A,37
	JRST SNDC

SNDBRK:	SKIPA A,[TELBRK]
SNDCD1:	PUSHJ P,CVOCT
SNDC:	MOVE B,A
	SKIPN A,SNDJFN(CNX)
	 POPJ P,
	BOUT
	MOVEI B,21
	MTOPR
	POPJ P,
; Set remote mode

SETREM:	SKIPE SNDJFN(CNX)
	 TRO F,REMOTF
	POPJ P,

DEFSKT:	SETZM WATFLG
	SETOM LODFLG
	MOVEI A,1
	MOVEM A,FSKT		; Default socket is 1
DEFSK0:	MOVE A,TERM
	CAIN A,37
	 POPJ P,
	MOVE TAB,SKTTAB
	PUSHJ P,SYMVAL		; Look for a possible socket
	JRST DEFSK0
; Other routines

.CVHST:	MOVE A,C
	MOVEM A,FHST
	MOVE C,2(B)
	MOVEM C,FHSTN
	CAME TAB,COMTAB
	 POPJ P,
	MOVE A,FHST
	JRST CONNX

; Check if host is up

HSTCHK:	PUSH P,A
	PUSH P,B
	MOVE A,[SIXBIT /IMPHRT/]
	SYSGT
	PUSH P,B
	MOVE A,FHSTN
	IDIVI A,=36
	HRLM A,0(P)
	POP P,A
	GETAB
	 SETZ A,
	ROT A,(B)
	SKIPGE A
	 AOS -2(P)
	POP P,B
	POP P,A
	POPJ P,

; Set socket number

.STFSK:	SKIPA A,2(B)
OCTFSK:	 PUSHJ P,CVOCT
	MOVEM A,FSKT
	POPJ P,

DOCOMT:	PUSHJ P,GCH
	PUSHJ P,ECHOIT
	CAIE A,37
	 JRST DOCOMT
	POPJ P,

CVOCT:	SKIPA C,[10]
CVDEC:	 MOVEI C,=10
	MOVE A,BPTR
	NIN
	 SETZ B,
	MOVE A,B
	POPJ P,
SEND:	CIS
	MOVE P,[XWD -100,SPDL-1]
	MOVE PTR,[POINT 7,LINBUF-1,34]
SEND0:	PUSHJ P,.PBIN
	ANDI A,177
	SKIPE XPARNT(CNX)	; Completely transparent?
	 JRST [	MOVE B,A	; Yes
		MOVE A,SNDJFN(CNX)
		BOUT
		MOVEI B,21
		MTOPR
		JRST SEND0]
	AOSN QUOTF
	 JRST SEND02		; Not special (may be shifted though)
	CAMN A,QUOT		; Quote character
	 JRST [	SETOM QUOTF	; Yes, remember
		JRST SEND0]
	CAMN A,BRKC		; Break substitute?
	 JRST [	MOVEI A,TELBRK	; Yes, send break
		JRST SEND3]
	CAMN A,SYNC		; Synch substitute
	 JRST [	PUSHJ P,SNDSNC	; Yes, send sync seq
		JRST SEND0]
	CAMN A,UNSFT		; Now for the shifts...unshift?
	 JRST [	FOR FL IN (<RAISEF(CNX)>,<LOWERF(CNX)>,UCASCF,LCASCF)<
		SETZM FL>	; clear all shift flags
		JRST SEND0]
	CAME A,LCASC
	 CAMN A,UCASC
	  JRST SETCAS
	CAME A,LCASL
	 CAMN A,UCASL
	  JRST SETCAS
SEND02:	CAIG A,136		; Regular character...needs shift?
	 CAIGE A,100
	  JRST SEND1		; Not upper case
	AOSE UCASCF		; Upper case.  if no upper case shift
	 PUSHJ P,SFTDWN		; Then see if down shift wanted
	JRST SEND3

SEND1:	CAIG A,176
	 CAIGE A,140
	  JRST SEND3		; Not lower case either
	AOSE LCASCF		; Lower case.  if no down shift
	 PUSHJ P,SFTUP		; Then shift up if wanted
	JRST SEND3

SETCAS:	SETZM LCASCF		; Clear character shifts
	SETZM UCASCF
	CAMN A,LCASC		; If lower case char prefix
	 JRST [	SETOM LCASCF	; Remember
		JRST SEND0]
	CAMN A,UCASC		; If upper case char prefix
	 JRST [	SETOM UCASCF	; Remember
		JRST SEND0]
	SETZM LOWERF(CNX)	; Clear shift locks
	SETZM RAISEF(CNX)
	CAMN A,LCASL
	 JRST [	SETOM LOWERF(CNX)
		JRST SEND0]
	CAMN A,UCASL
	 JRST [	SETOM RAISEF(CNX)
		JRST SEND0]
;	JRST SEND3
SEND3:	SKIPN LNBFF(CNX)	; If not line buffering
	 PUSHJ P,SNDBUF		; Send any stuff already buffered
	CAIN A,37
	 JRST [	MOVEI A,15
		PUSHJ P,SNDDO
		SETCM A,LFCRF(CNX)	; Get complement of switch
		HRRI A,12	; Line feed
		JRST .+1]
	PUSHJ P,SNDDO
	HRRZS A
	CAIE A,12
	 CAIN A,33
	  PUSHJ P,SNDBUF
	JRST SEND0
SFTDWN:	AOSE LCASCF
	SKIPE LOWERF(CNX)
	 TRO A,140
	POPJ P,

SFTUP:	AOSE UCASCF
	SKIPE RAISEF(CNX)
	 TRZ A,40
	POPJ P,

SENDO:	SKIPA A,CBFCHR
SENDE:	 MOVE A,ESCAPE
	JRST SEND3

SNDBUF:	CAMN PTR,[POINT 7,LINBUF-1,34]
	 POPJ P,
	PUSHJ P,TRMST
	MOVE PTR,[POINT 7,LINBUF-1,34]
	MOVE B,PTR
	MOVE A,SNDJFN(CNX)
	SETZ C,
	SOUT
	MOVEI B,21
	MTOPR
	POPJ P,

SNDDO:	SKIPE LNBFF(CNX)
	 JRST SNDLBF
	MOVE B,A
	MOVE A,SNDJFN(CNX)
	BOUT
	PUSH P,B
	MOVEI B,21
	MTOPR
	POP P,B
	MOVE A,B
SNDECH:	JUMPL A,CPOPJ		; Never echo ch with -1 lh
	SKIPN HDX		; If hdx terminal
	 SKIPN ELCLF(CNX)		; If not local echo
	  POPJ P,		; Then done
	MOVE B,ECHCOC(CNX)
	ROT B,(A)		; Prepare to test coc
	CAIGE A,40		; If not control
	 JUMPGE B,CPOPJ
	PUSHJ P,.PEOUT		; Echo
	POPJ P,
SNDLBF:	CAIE A,"A"-100
	 CAIN A,"H"-100
	  JRST [CAMN PTR,[POINT 7,LINBUF-1,34]
		 JRST [	MOVEI A,7
			PUSHJ P,.PBOUT
			POPJ P,]
		MOVEI A,"\"
		PUSHJ P,.PBOUT
		LDB A,PTR
		PUSHJ P,.PBOUT
		MOVE A,PTR
		BKJFN
		 JRST 4,.
		MOVEM A,PTR
		POPJ P,]
	CAIN A,"X"-100
	 JRST [	MOVEI A,"#"
		PUSHJ P,.PBOUT
		PUSHJ P,.PBOUT
		MOVEI A,37
		PUSHJ P,.PBOUT
		MOVE PTR,[POINT 7,LINBUF-1,34]
		POPJ P,]
	CAIN A,"R"-100
	 JRST [	MOVEI A,37
		PUSHJ P,.PBOUT
		PUSHJ P,TRMST
		MOVE A,[POINT 7,LINBUF-1,34]
		PUSHJ P,.PSOUT
		POPJ P,]
	IDPB A,PTR
	SKIPE ELCLF(CNX)
	 PUSHJ P,SNDECH
	POPJ P,
RECV:	CIS
	MOVE A,RCVJFN(CNX)
	MOVEI B,24
	MOVSI C,017777
	MTOPR			; Ins interrupts on channel 1
	MOVE P,[XWD -100,SPDL-1]
	SETZM CBFCNT(CNX)
RECVY:	SETZM SAVINC(CNX)	; Loop to here to reset buffer
	MOVE A,[POINT 7,SAVBUF]
	MOVEM A,SAVINP(CNX)
	MOVEM A,SAVONP(CNX)
RECV0:	SKIPE SAVSWT(CNX)	; Saving output up?
	 JRST RECVR		; Yes, check if full and do it
	SKIPE SAVINC(CNX)	; No, any saved characters?
	 JRST RECVU		; Yes, unsave them
	JRST RECVB0		; No, get next input

RECVR:	MOVEI A,SAVBFS*5-5
	CAMG A,SAVINC(CNX)
RECVH:	 HALTF
RECVB0:	MOVE A,RCVJFN(CNX)
RECVB:	BIN
	CAIL B,200
	 JRST RCVCTL		; Process telnet control character
	SKIPGE CBFCNT(CNX)
	 JRST RECV0		; Flushing output
	SKIPE SAVSWT(CNX)	; Saving up the output?
	 JRST RECVS		; Yes, go put it in buffer
RECV1:	SKIPE CLROBF
	 JRST RECVFL
	SKIPLE A,DIVJFN
	 JRST RECVX
	MOVE A,B
	PUSHJ P,.PEOUT
	JRST RECV0

RECVU:	SKIPE CLROBF		; Clear output buffer?
	 JRST [	MOVE A,SAVINP(CNX)
		MOVEM A,SAVONP(CNX)
		SETZM SAVINC(CNX)
		LDB B,SAVONP(CNX)
		JRST RECVFL]
	MOVNI A,SAVBFS		; No
	ADD A,SAVONP(CNX)	; Wrapped pointer if needed
	CAMN A,[POINT 7,SAVBUF-1,34]
	 MOVEM A,SAVONP(CNX)	; Wrap pointer
	ILDB B,SAVONP(CNX)	; Get byte
	SOS SAVINC(CNX)		; Account
	JRST RECV1		; Go put it out
RECVS:	MOVNI A,SAVBFS		; Prepare wrapped pointer
	ADD A,SAVINP(CNX)
	CAMN A,[POINT 7,SAVBUF-1,34]
	 MOVEM A,SAVINP(CNX)	; And use it if needed
	IDPB B,SAVINP(CNX)	; Store character
	AOS A,SAVINC(CNX)	; Account
	SKIPE SWOFLG		; Swo and
	 CAIE A,1		; First character?
	  JRST RECV0		; No
	MOVEI A,101
	DOBE
	HRROI A,[ASCIZ /
Output waiting from connection /]
	PUSHJ P,.PSOUT
	MOVE A,CNX
	IMULI A,3
	HRROI A,CONNAM(A)
	PUSHJ P,.PSOUT
	MOVEI A,37
	PUSHJ P,.PBOUT
	JRST RECV0

RECVX:	BOUT
	SKIPE DIVSWT
	 JRST RECVN
	SKIPLE A,SCRJFN
	 BOUT
	MOVE A,B
	PUSHJ P,.PEOUT
RECVN:	CAIE B,12
	 JRST RECV0
	MOVEI A,101
	SOBE
	 JRST [	HRROI A,[ASCIZ /...
/]
		SKIPN DIVSWT
		 PUSHJ P,.PSOUT
		SETOM DIVSWT
		JRST RECV0]
	SETZM DIVSWT
	JRST RECV0
RECVFL:	MOVEM B,D
	MOVE A,RCVJFN(CNX)
	SKIPN SAVINC(CNX)
	SIBE
	 JRST RECV0
	MOVEI C,2
RECVF1:	MOVEI A,=500
	DISMS
	MOVE A,RCVJFN(CNX)
	SIBE
	 JRST RECV0
	SOJG C,RECVF1
	SETZM CLROBF
	MOVEI A,37
	PUSHJ P,.PBOUT
	MOVE B,D
	JRST RECV1

IOERR:	HRROI A,[ASCIZ /
IO error for connection /]
	JRST GENABN

RCVEOF:	MOVE A,[XWD 10000,RECVH]
	MOVEM A,FKRET2
	SKIPN SAVSWT(CNX)
	 SKIPE SAVINC(CNX)
	  DEBRK			; Delay eof response until buffer gone
	HRROI A,[ASCIZ /Remote disconnect of /]
GENABN:	PUSH P,A
	AOSE ABNLCK		; Wait for abnormal interrupt handler
	 JRST [	MOVEI A,=1000
		DISMS
		JRST .-1]
	POP P,A
	PUSHJ P,.PSOUT
	MOVE A,CNX
	IMULI A,3
	HRROI A,CONNAM(A)
	PUSHJ P,.PSOUT
	MOVEM CNX,ABNCNX
	MOVEI A,-1
	MOVSI B,(1⊗<43-ABNCHN>)
	IIC			; Initiate abnormal interrupt in superior
	MOVEI A,=100000
	DISMS			; And hang
	JRST .-2
RCVCTL:	CAIN B,TELASC
	 JRST RECV0		; Ignore telasc
	CAIGE B,205
	 JRST RCTLDT-200(B)
	HRROI A,[ASCIZ /Undefined telnet control /]
	PUSHJ P,.PSOUT
	MOVEI A,101
	MOVEI C,10
	PUSHJ P,.NOUT
	 JFCL
	JRST RECV0

RCTLDT:	JRST $CFOBF
	JRST PRBRK
	JRST RECV0
	JRST ECHOFF
	JRST ECHON

$CFOBF:	MOVEI A,1
	EXCH A,CBFCNT(CNX)	; Set to 1
	JUMPE A,CFOBF0		; This came first, clear output
	SETZM CBFCNT(CNX)	; Came second, clear
	JUMPL A,RECV0		; Jump if not out of phase
	MOVEI A,=5000
	DISMS			; Wait for any possible ins
	SETZM CBFCNT(CNX)	; And cancel it's remainder
	JRST RECV0

CFOBF0:	MOVEI A,101
	SKIPN SAVSWT(CNX)
	 CFOBF
	JRST RECVY
RCVINS:	PUSH P,A
	SKIPLE CBFCNT(CNX)
	 JRST [	SETZM CBFCNT(CNX)
		JRST RCVINX]
	SETOM CBFCNT(CNX)
	MOVEI A,101
	SKIPN SAVSWT(CNX)
	 CFOBF
	SETZM SAVINC(CNX)
	MOVE A,[POINT 7,SAVBUF]
	MOVEM A,SAVINP(CNX)
	MOVEM A,SAVONP(CNX)
	HRRZ A,FKRET2
	CAIE A,RECVH
	 CAIN A,RECVH+1
	  JRST [MOVEI A,RECV0
		HRRM A,FKRET2
		JRST RCVINX]
RCVINX:	POP P,A
	DEBRK

PRBRK:	SKIPLE A,BRKC
	 JRST [	PUSHJ P,.PBOUT
		JRST RECV0]
	HRROI A,[ASCIZ /'break'/]
	PUSHJ P,.PSOUT
	JRST RECV0

ECHOFF:	SKIPE HDX
	 JRST [	MOVEI B,TELNEC
		MOVE A,SNDJFN(CNX)
		BOUT		; Tell him he can't
		MOVEI B,21
		MTOPR
		JRST RECV0]
	TDZA A,A
ECHON:	 SETO A,
	MOVEM A,ELCLF(CNX)
	JRST RECV0

USE VARPC
VARS:	VAR
FMODSW:	BLOCK 7
SPARE:	BLOCK 3
NMODSW←←.-FMODSW
EVARS:	USE

END START